﻿using GuoZhiQi.MiddleCache.Common.Serialization;
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Configuration;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.Globalization;
using System.IO;
using System.IO.Compression;
using System.Net.Mail;
using System.Reflection;
using System.Runtime.Serialization.Formatters.Binary;
using System.Runtime.Serialization.Formatters.Soap;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
 

namespace GuoZhiQi.MiddleCache.Common
{
    /// <summary>
    ///提供图片功能类
    /// </summary>
    public static class ImageUtil
    {
        #region Get stream and image info.

        /// <summary>
        /// 从stream 流中读取二进制文件
        /// </summary>
        /// <param name="stream"></param>
        /// <returns></returns>
        public static byte[] GetByteFromStream(Stream stream)
        {
            stream.Position = 0;
            BinaryReader reader = new BinaryReader(stream);
            int len = (int)stream.Length;
            stream.Position = 0;
            return reader.ReadBytes(len);
        }
        /// <summary>
        /// 从二进制中获取图片文件信息
        /// </summary>
        /// <param name="imgByte"></param>
        /// <returns></returns>
        public static Image GetImageFromByte(byte[] imgByte)
        {
            MemoryStream memStream = new MemoryStream(imgByte);
            Image fullSizeImg = Image.FromStream(memStream);
            return fullSizeImg;
        }
        /// <summary>
        /// 从图片中获取二进制信息
        /// </summary>
        /// <param name="image"></param>
        /// <param name="imageFormat"></param>
        /// <returns></returns>
        public static byte[] GetByteFromImage(Image image, ImageFormat imageFormat)
        {
            byte[] imageData;
            using (MemoryStream stream = new MemoryStream())
            {
                image.Save(stream, imageFormat);
                imageData = ImageUtil.GetByteFromStream(stream);
            }
            return imageData;
        }
        /// <summary>
        /// 从二进制中获取图片格式
        /// </summary>
        /// <param name="imgByte"></param>
        /// <returns></returns>
        public static ImageFormat GetImageFormatFromByte(byte[] imgByte)
        {
            ImageFormat imgFormat = ImageFormat.Jpeg;
            using (Image img = ImageUtil.GetImageFromByte(imgByte))
            {
                imgFormat = img.GetImageFormat();
            }

            return imgFormat;
        }
        /// <summary>
        /// 从图片中获取图片格式
        /// </summary>
        /// <param name="img"></param>
        /// <returns></returns>
        public static ImageFormat GetImageFormat(this System.Drawing.Image img)
        {
            if (img.RawFormat.Equals(ImageFormat.Jpeg))
                return ImageFormat.Jpeg;
            if (img.RawFormat.Equals(ImageFormat.Bmp))
                return ImageFormat.Bmp;
            if (img.RawFormat.Equals(ImageFormat.Png))
                return ImageFormat.Png;
            if (img.RawFormat.Equals(ImageFormat.Emf))
                return ImageFormat.Emf;
            if (img.RawFormat.Equals(ImageFormat.Exif))
                return ImageFormat.Exif;
            if (img.RawFormat.Equals(ImageFormat.Gif))
                return ImageFormat.Gif;
            if (img.RawFormat.Equals(ImageFormat.Icon))
                return ImageFormat.Icon;
            if (img.RawFormat.Equals(ImageFormat.MemoryBmp))
                return ImageFormat.MemoryBmp;
            if (img.RawFormat.Equals(ImageFormat.Tiff))
                return ImageFormat.Tiff;
            else
                return ImageFormat.Wmf;
        }

        #endregion Get stream and image info.

        #region Resize image.
        /// <summary>
        /// 更改二进制文件图片的大小
        /// </summary>
        /// <param name="imgData"></param>
        /// <param name="newsize"></param>
        /// <returns></returns>
        public static byte[] ResizePicture(byte[] imgData, Size newsize)
        {
            return ResizePicture(imgData, newsize, ImageFormat.Jpeg);
        }

        public static byte[] ResizePicture(byte[] imgData, Size newsize, ImageFormat imageFormat)
        {
            return ResizePicture(imgData, newsize, imageFormat, null, null);
        }

        public static byte[] ResizePicture(byte[] imgData, Size newsize, ImageFormat imageFormat, Color? fillColor, AnchorPosition? anchor)
        {
            bool useFill = false;
            if (fillColor.HasValue)
                useFill = true;
            else
                fillColor = Color.White;

            if (!anchor.HasValue)
                anchor = AnchorPosition.Middle;

            byte[] oData;

            using (Bitmap newImg = new Bitmap(newsize.Width, newsize.Height, PixelFormat.Format24bppRgb))
            using (Bitmap oldImg = (Bitmap)ImageUtil.GetImageFromByte(imgData))
            {
                newImg.SetResolution(oldImg.HorizontalResolution,
                        oldImg.VerticalResolution);

                using (Graphics g = Graphics.FromImage(newImg))
                using (MemoryStream stream = new MemoryStream())
                {
                    g.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
                    g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
                    g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;

                    Size targetSize = new Size(newImg.Width, newImg.Height);
                    Rectangle sourcePicture = new Rectangle(0, 0, oldImg.Width, oldImg.Height);

                    Rectangle targetPicture = CalculateBestFitRect(new Size(oldImg.Width, oldImg.Height), targetSize, useFill, anchor.Value);

                    g.Clear(fillColor.Value);
                    g.DrawImage(oldImg, targetPicture, sourcePicture, GraphicsUnit.Pixel);

                    g.Save();
                    newImg.Save(stream, imageFormat);

                    oData = ImageUtil.GetByteFromStream(stream);
                }
            }
            return oData;
        }

        #endregion Resize image.

        #region Math helpers.
        /// <summary>
        /// 图片位置锚点信息
        /// </summary>
        public enum AnchorPosition
        {
            Top = 1,
            Bottom = 2,
            Left = 3,
            Right = 4,
            Middle = 5
        }

        public static Rectangle CalculateBestFitRect(Size originalSize, Size toFit, bool useFill, AnchorPosition anchor = AnchorPosition.Middle)
        {
            int sourceWidth = originalSize.Width;
            int sourceHeight = originalSize.Height;
            int destX = 0;
            int destY = 0;

            float nPercent = 0;
            float nPercentW = 0;
            float nPercentH = 0;

            if (!useFill)
            {
                nPercentW = ((float)toFit.Width / (float)sourceWidth);
                nPercentH = ((float)toFit.Height / (float)sourceHeight);

                if (nPercentH < nPercentW)
                {
                    nPercent = nPercentW;
                    switch (anchor)
                    {
                        case AnchorPosition.Top:
                            destY = 0;
                            break;
                        case AnchorPosition.Bottom:
                            destY = (int)
                                (toFit.Height - (sourceHeight * nPercent));
                            break;
                        default:
                            destY = (int)
                                ((toFit.Height - (sourceHeight * nPercent)) / 2);
                            break;
                    }
                }
                else
                {
                    nPercent = nPercentH;
                    switch (anchor)
                    {
                        case AnchorPosition.Left:
                            destX = 0;
                            break;
                        case AnchorPosition.Right:
                            destX = (int)
                              (toFit.Width - (sourceWidth * nPercent));
                            break;
                        default:
                            destX = (int)
                              ((toFit.Width - (sourceWidth * nPercent)) / 2);
                            break;
                    }
                }

                int destWidth = (int)(sourceWidth * nPercent);
                int destHeight = (int)(sourceHeight * nPercent);

                return new Rectangle(destX, destY, destWidth, destHeight);
            }
            else
            {
                nPercentW = ((float)toFit.Width / (float)sourceWidth);
                nPercentH = ((float)toFit.Height / (float)sourceHeight);
                if (nPercentH < nPercentW)
                {
                    nPercent = nPercentH;
                    destX = System.Convert.ToInt16((toFit.Width -
                                  (sourceWidth * nPercent)) / 2);
                }
                else
                {
                    nPercent = nPercentW;
                    destY = System.Convert.ToInt16((toFit.Height -
                                  (sourceHeight * nPercent)) / 2);
                }

                int destWidth = (int)(sourceWidth * nPercent);
                int destHeight = (int)(sourceHeight * nPercent);

                return new Rectangle(destX, destY, destWidth, destHeight);
            }
        }

        #endregion Math helpers.
    }

    public static class StreamUtil
    {
        public static byte[] ReadToEnd(System.IO.Stream stream)
        {
            long originalPosition = 0;

            if (stream.CanSeek)
            {
                originalPosition = stream.Position;
                stream.Position = 0;
            }

            try
            {
                byte[] readBuffer = new byte[4096];

                int totalBytesRead = 0;
                int bytesRead;

                while ((bytesRead = stream.Read(readBuffer, totalBytesRead, readBuffer.Length - totalBytesRead)) > 0)
                {
                    totalBytesRead += bytesRead;

                    if (totalBytesRead == readBuffer.Length)
                    {
                        int nextByte = stream.ReadByte();
                        if (nextByte != -1)
                        {
                            byte[] temp = new byte[readBuffer.Length * 2];
                            Buffer.BlockCopy(readBuffer, 0, temp, 0, readBuffer.Length);
                            Buffer.SetByte(temp, totalBytesRead, (byte)nextByte);
                            readBuffer = temp;
                            totalBytesRead++;
                        }
                    }
                }

                byte[] buffer = readBuffer;
                if (readBuffer.Length != totalBytesRead)
                {
                    buffer = new byte[totalBytesRead];
                    Buffer.BlockCopy(readBuffer, 0, buffer, 0, totalBytesRead);
                }
                return buffer;
            }
            finally
            {
                if (stream.CanSeek)
                {
                    stream.Position = originalPosition;
                }
            }
        }
    }

    /// <summary>
    /// Provides common value parsing functionalities.
    /// </summary>
    public static class NumberParser
    {
        public static byte? ParseByte(string text)
        {
            byte value;
            bool success = Byte.TryParse(text, out value);
            if (success)
                return value;
            else
                return null;
        }

        #region ParseInt.

        /// <summary>
        /// Converts the string representation of a number to its 32-bit signed integer equivalent.
        /// </summary>
        /// <param name="textRepresentation">A string containing a number to convert.</param>
        /// <returns>A number if conversion succeeded; <b>null</b> otherwise.</returns>
        public static int? ParseInt(string textRepresentation)
        {
            if (string.IsNullOrEmpty(textRepresentation))
                return null;

            textRepresentation = textRepresentation.Trim();
            int number;
            bool isParsed = int.TryParse(textRepresentation, out number);
            return (isParsed) ? (int?)number : null;
        }

        /// <summary>
        /// Converts the string representation of a number to its 32-bit signed integer equivalent.
        /// </summary>
        /// <param name="textRepresentation">A string containing a number to convert.</param>
        /// <param name="formatter">An object which contains an <see cref="System.IFormatProvider"/> and
        /// <see cref="NumberStyles"/> objects that supply culture-specific formatting information about <b>textRepresentation</b>.</param>
        /// <returns>A number if conversion succeeded; <b>null</b> otherwise.</returns>
        public static int? ParseInt(string textRepresentation, IMessageFormatter formatter)
        {
            return ParseInt(textRepresentation, formatter.IntStyle, formatter.IntProvider);
        }

        /// <summary>
        /// Converts the string representation of a number to its 32-bit signed integer equivalent.
        /// </summary>
        /// <param name="textRepresentation">A string containing a number to convert.</param>
        /// <param name="provider">An <see cref="System.IFormatProvider"/> object that supplies culture-specific
        /// formatting information about <b>textRepresentation</b>.</param>
        /// <returns>A number if conversion succeeded; <b>null</b> otherwise.</returns>
        public static int? ParseInt(string textRepresentation, IFormatProvider provider)
        {
            return ParseInt(textRepresentation, NumberStyles.Integer, provider);
        }

        /// <summary>
        /// Converts the string representation of a number to its 32-bit signed integer equivalent.
        /// </summary>
        /// <param name="textRepresentation">A string containing a number to convert.</param>
        /// <param name="style">A bitwise combination of <see cref="System.Globalization.NumberStyles"/> values
        /// that indicates the permitted format of textRepresentation. A typical value to specify is
        /// <see cref="System.Globalization.NumberStyles.Integer"/>.</param>
        /// <param name="provider">An <see cref="System.IFormatProvider"/> object that supplies culture-specific
        /// formatting information about <b>textRepresentation</b>.</param>
        /// <returns>A number if conversion succeeded; <b>null</b> otherwise.</returns>
        public static int? ParseInt(string textRepresentation, NumberStyles style, IFormatProvider provider)
        {
            if (string.IsNullOrEmpty(textRepresentation))
                return null;

            textRepresentation = textRepresentation.Trim();
            int number;
            bool isParsed = int.TryParse(textRepresentation, style, provider, out number);
            return (isParsed) ? (int?)number : null;
        }

        #endregion ParseInt.

        #region ParseLong.

        /// <summary>
        /// Converts the string representation of a number to its 64-bit signed integer equivalent.
        /// </summary>
        /// <param name="textRepresentation">A string containing a number to convert.</param>
        /// <returns>A number if conversion succeeded; <b>null</b> otherwise.</returns>
        public static long? ParseLong(string textRepresentation)
        {
            if (string.IsNullOrEmpty(textRepresentation))
                return null;

            textRepresentation = textRepresentation.Trim();
            long number;
            bool isParsed = long.TryParse(textRepresentation, out number);
            return (isParsed) ? (long?)number : null;
        }

        /// <summary>
        /// Converts the string representation of a number to its 64-bit signed integer equivalent.
        /// </summary>
        /// <param name="textRepresentation">A string containing a number to convert.</param>
        /// <param name="formatter">An object which contains an <see cref="System.IFormatProvider"/> and
        /// <see cref="NumberStyles"/> objects that supply culture-specific formatting information about <b>textRepresentation</b>.</param>
        /// <returns>A number if conversion succeeded; <b>null</b> otherwise.</returns>
        public static long? ParseLong(string textRepresentation, IMessageFormatter formatter)
        {
            return ParseLong(textRepresentation, formatter.IntStyle, formatter.IntProvider);
        }

        /// <summary>
        /// Converts the string representation of a number to its 64-bit signed integer equivalent.
        /// </summary>
        /// <param name="textRepresentation">A string containing a number to convert.</param>
        /// <param name="provider">An <see cref="System.IFormatProvider"/> object that supplies culture-specific
        /// formatting information about <b>textRepresentation</b>.</param>
        /// <returns>A number if conversion succeeded; <b>null</b> otherwise.</returns>
        public static long? ParseLong(string textRepresentation, IFormatProvider provider)
        {
            return ParseLong(textRepresentation, NumberStyles.Integer, provider);
        }

        /// <summary>
        /// Converts the string representation of a number to its 64-bit signed integer equivalent.
        /// </summary>
        /// <param name="textRepresentation">A string containing a number to convert.</param>
        /// <param name="style">A bitwise combination of <see cref="System.Globalization.NumberStyles"/> values
        /// that indicates the permitted format of textRepresentation. A typical value to specify is
        /// <see cref="System.Globalization.NumberStyles.Integer"/>.</param>
        /// <param name="provider">An <see cref="System.IFormatProvider"/> object that supplies culture-specific
        /// formatting information about <b>textRepresentation</b>.</param>
        /// <returns>A number if conversion succeeded; <b>null</b> otherwise.</returns>
        public static long? ParseLong(string textRepresentation, NumberStyles style, IFormatProvider provider)
        {
            if (string.IsNullOrEmpty(textRepresentation))
                return null;

            textRepresentation = textRepresentation.Trim();
            long number;
            bool isParsed = long.TryParse(textRepresentation, style, provider, out number);
            return (isParsed) ? (long?)number : null;
        }

        #endregion ParseLong.

        #region ParseFloat.

        /// <summary>
        /// Converts the string representation of a number to its single-precision floating point number equivalent.
        /// </summary>
        /// <param name="textRepresentation">A string containing a number to convert.</param>
        /// <param name="formatter">An object which contains an <see cref="System.IFormatProvider"/> and
        /// <see cref="NumberStyles"/> objects that supply culture-specific formatting information about <b>textRepresentation</b>.</param>
        /// <returns>A number if conversion succeeded; <b>null</b> otherwise.</returns>
        public static float? ParseFloat(string textRepresentation, IMessageFormatter formatter)
        {
            return ParseFloat(textRepresentation, formatter.RealStyle, formatter.RealProvider);
        }

        /// <summary>
        /// Converts the string representation of a number to its single-precision floating point number equivalent.
        /// </summary>
        /// <param name="textRepresentation">A string containing a number to convert.</param>
        /// <param name="provider">An <see cref="System.IFormatProvider"/> object that supplies culture-specific
        /// formatting information about <b>textRepresentation</b>.</param>
        /// <returns>A number if conversion succeeded; <b>null</b> otherwise.</returns>
        public static float? ParseFloat(string textRepresentation, IFormatProvider provider)
        {
            return ParseFloat(textRepresentation, NumberStyles.Float | NumberStyles.AllowThousands, provider);
        }

        /// <summary>
        /// Converts the string representation of a number to its single-precision floating point number equivalent.
        /// </summary>
        /// <param name="textRepresentation">A string containing a number to convert.</param>
        /// <param name="style">A bitwise combination of <see cref="System.Globalization.NumberStyles"/> values
        /// that indicates the permitted format of textRepresentation. A typical value to specify is
        /// <see cref="System.Globalization.NumberStyles.Float"/> combined with <see cref="System.Globalization.NumberStyles.AllowThousands"/>.</param>
        /// <param name="provider">An <see cref="System.IFormatProvider"/> object that supplies culture-specific
        /// formatting information about <b>textRepresentation</b>.</param>
        /// <returns>A number if conversion succeeded; <b>null</b> otherwise.</returns>
        public static float? ParseFloat(string textRepresentation, NumberStyles style, IFormatProvider provider)
        {
            float number;
            bool isParsed = float.TryParse(textRepresentation, style, provider, out number);
            return (isParsed) ? (float?)number : null;
        }

        #endregion ParseFloat.

        #region ParseDouble.

        /// <summary>
        /// Converts the string representation of a number to its double-precision floating point number equivalent.
        /// </summary>
        /// <param name="textRepresentation">A string containing a number to convert.</param>
        /// <param name="formatter">An object which contains an <see cref="System.IFormatProvider"/> and
        /// <see cref="NumberStyles"/> objects that supply culture-specific formatting information about <b>textRepresentation</b>.</param>
        /// <returns>A number if conversion succeeded; <b>null</b> otherwise.</returns>
        public static double? ParseDouble(string textRepresentation, IMessageFormatter formatter)
        {
            return ParseDouble(textRepresentation, formatter.RealStyle, formatter.RealProvider);
        }

        /// <summary>
        /// Converts the string representation of a number to its double-precision floating point number equivalent.
        /// </summary>
        /// <param name="textRepresentation">A string containing a number to convert.</param>
        /// <param name="provider">An <see cref="System.IFormatProvider"/> object that supplies culture-specific
        /// formatting information about <b>textRepresentation</b>.</param>
        /// <returns>A number if conversion succeeded; <b>null</b> otherwise.</returns>
        public static double? ParseDouble(string textRepresentation, IFormatProvider provider)
        {
            return ParseDouble(textRepresentation, NumberStyles.Float | NumberStyles.AllowThousands, provider);
        }

        /// <summary>
        /// Converts the string representation of a number to its double-precision floating point number equivalent.
        /// </summary>
        /// <param name="textRepresentation">A string containing a number to convert.</param>
        /// <param name="style">A bitwise combination of <see cref="System.Globalization.NumberStyles"/> values
        /// that indicates the permitted format of textRepresentation. A typical value to specify is
        /// <see cref="System.Globalization.NumberStyles.Float"/> combined with <see cref="System.Globalization.NumberStyles.AllowThousands"/>.</param>
        /// <param name="provider">An <see cref="System.IFormatProvider"/> object that supplies culture-specific
        /// formatting information about <b>textRepresentation</b>.</param>
        /// <returns>A number if conversion succeeded; <b>null</b> otherwise.</returns>
        public static double? ParseDouble(string textRepresentation, NumberStyles style, IFormatProvider provider)
        {
            double number;
            bool isParsed = double.TryParse(textRepresentation, style, provider, out number);
            return (isParsed) ? (double?)number : null;
        }

        #endregion ParseDouble.

        #region ParseDecimal.

        /// <summary>
        /// Converts the string representation of a number to its <b>Decimal</b> equivalent.
        /// </summary>
        /// <param name="textRepresentation">A string containing a number to convert.</param>
        /// <param name="formatter">An object which contains an <see cref="System.IFormatProvider"/> and
        /// <see cref="NumberStyles"/> objects that supply culture-specific formatting information about <b>textRepresentation</b>.</param>
        /// <returns>A number if conversion succeeded; <b>null</b> otherwise.</returns>
        public static decimal? ParseDecimal(string textRepresentation, IMessageFormatter formatter)
        {
            return ParseDecimal(textRepresentation, formatter.RealStyle, formatter.RealProvider);
        }

        /// <summary>
        /// Converts the string representation of a number to its <b>Decimal</b> equivalent.
        /// </summary>
        /// <param name="textRepresentation">A string containing a number to convert.</param>
        /// <param name="provider">An <see cref="System.IFormatProvider"/> object that supplies culture-specific
        /// formatting information about <b>textRepresentation</b>.</param>
        /// <returns>A number if conversion succeeded; <b>null</b> otherwise.</returns>
        public static decimal? ParseDecimal(string textRepresentation, IFormatProvider provider)
        {
            return ParseDecimal(textRepresentation, NumberStyles.Number, provider);
        }

        /// <summary>
        /// Converts the string representation of a number to its <b>Decimal</b> equivalent.
        /// </summary>
        /// <param name="textRepresentation">A string containing a number to convert.</param>
        /// <param name="style">A bitwise combination of <see cref="System.Globalization.NumberStyles"/> values
        /// that indicates the permitted format of textRepresentation. A typical value to specify is
        /// <see cref="System.Globalization.NumberStyles.Number"/>.</param>
        /// <param name="provider">An <see cref="System.IFormatProvider"/> object that supplies culture-specific
        /// formatting information about <b>textRepresentation</b>.</param>
        /// <returns>A number if conversion succeeded; <b>null</b> otherwise.</returns>
        public static decimal? ParseDecimal(string textRepresentation, NumberStyles style, IFormatProvider provider)
        {
            if (string.IsNullOrEmpty(textRepresentation))
                return null;

            textRepresentation = textRepresentation.Trim();
            decimal number;
            bool isParsed = decimal.TryParse(textRepresentation, style, provider, out number);
            return (isParsed) ? (decimal?)number : null;
        }

        #endregion ParseDecimal.

        #region IsInteger.

        /// <summary>
        /// Checks whether the given string represents an integer value.
        /// </summary>
        /// <returns><b>true</b> if the given string is an integer; <b>false</b> otherwise.</returns>
        public static bool IsInteger(string str)
        {
            long? integer = ParseLong(str);
            return integer.HasValue;
        }

        /// <summary>
        /// Checks whether the given string represents an integer value.
        /// </summary>
        /// <param name="str">A string to test.</param>
        /// <param name="formatter">An object which contains an <see cref="System.IFormatProvider"/> and
        /// <see cref="NumberStyles"/> objects that supply culture-specific formatting information about <b>textRepresentation</b>.</param>
        /// <returns><b>true</b> if the given string is an integer; <b>false</b> otherwise.</returns>
        public static bool IsInteger(string str, IMessageFormatter formatter)
        {
            long? integer = ParseLong(str, formatter);
            return integer.HasValue;
        }

        /// <summary>
        /// Checks whether the given string represents an integer value.
        /// </summary>
        /// <param name="str">A string to test.</param>
        /// <param name="provider">An <see cref="System.IFormatProvider"/> object that supplies culture-specific
        /// formatting information about <b>str</b>.</param>
        /// <returns><b>true</b> if the given string is an integer; <b>false</b> otherwise.</returns>
        public static bool IsInteger(string str, IFormatProvider provider)
        {
            long? integer = ParseLong(str, provider);
            return integer.HasValue;
        }

        /// <summary>
        /// Checks whether the given string represents an integer value.
        /// </summary>
        /// <param name="str">A string to test.</param>
        /// <param name="style">A bitwise combination of <see cref="System.Globalization.NumberStyles"/> values
        /// that indicates the permitted format of textRepresentation. A typical value to specify is
        /// <see cref="System.Globalization.NumberStyles.Integer"/>.</param>
        /// <param name="provider">An <see cref="System.IFormatProvider"/> object that supplies culture-specific
        /// formatting information about <b>textRepresentation</b>.</param>
        /// <returns><b>true</b> if the given string is an integer; <b>false</b> otherwise.</returns>
        public static bool IsInteger(string str, NumberStyles style, IFormatProvider provider)
        {
            long? integer = ParseLong(str, style, provider);
            return integer.HasValue;
        }

        #endregion IsInteger.

        #region IsNumber.

        /// <summary>
        /// Checks whether the given string represents a number.
        /// </summary>
        /// <param name="str">A string to test.</param>
        /// <param name="formatter">An object which contains an <see cref="System.IFormatProvider"/> and
        /// <see cref="NumberStyles"/> objects that supply culture-specific formatting information about <b>textRepresentation</b>.</param>
        /// <returns><b>true</b> if the given string is an integer; <b>false</b> otherwise.</returns>
        public static bool IsNumber(string str, IMessageFormatter formatter)
        {
            double? number = ParseDouble(str, formatter.RealProvider);
            return number.HasValue;
        }

        /// <summary>
        /// Checks whether the given string represents a number.
        /// </summary>
        /// <param name="str">A string to test.</param>
        /// <param name="provider">An <see cref="System.IFormatProvider"/> object that supplies culture-specific
        /// formatting information about <b>str</b>.</param>
        /// <returns><b>true</b> if the given string is an integer; <b>false</b> otherwise.</returns>
        public static bool IsNumber(string str, IFormatProvider provider)
        {
            double? number = ParseDouble(str, provider);
            return number.HasValue;
        }

        /// <summary>
        /// Checks whether the given string represents a number.
        /// </summary>
        /// <param name="str">A string to test.</param>
        /// <param name="style">A bitwise combination of <see cref="System.Globalization.NumberStyles"/> values
        /// that indicates the permitted format of textRepresentation. A typical value to specify is
        /// <see cref="System.Globalization.NumberStyles.Number"/>.</param>
        /// <param name="provider">An <see cref="System.IFormatProvider"/> object that supplies culture-specific
        /// formatting information about <b>str</b>.</param>
        /// <returns><b>true</b> if the given string is an integer; <b>false</b> otherwise.</returns>
        public static bool IsNumber(string str, NumberStyles style, IFormatProvider provider)
        {
            double? number = ParseDouble(str, style, provider);
            return number.HasValue;
        }

        #endregion IsNumber.

        #region ParseEnum.

        /// <summary>
        /// Converts the string representation of the name or numeric value of one or more enumerated constants to an equivalent enumerated object.
        /// </summary>
        /// <typeparam name="T">The <see cref="Type"/> of the enumeration.</typeparam>
        /// <param name="textRepresentation">A string containing the name or value to convert.</param>
        /// <returns>An object of type enumType whose value is represented by value. <b>null</b> if conversion fails.</returns>
        public static T? ParseEnum<T>(string textRepresentation) where T : struct
        {
            if (string.IsNullOrEmpty(textRepresentation))
                return null;

            try
            {
                return (T)Enum.Parse(typeof(T), textRepresentation);
            }
            catch
            {
                return null;
            }
        }

        /// <summary>
        /// Converts the string representation of the name or numeric value of one or more enumerated constants to an equivalent enumerated object.
        /// </summary>
        /// <typeparam name="T">The <see cref="Type"/> of the enumeration.</typeparam>
        /// <param name="textRepresentation">A string containing the name or value to convert.</param>
        /// <param name="ignoreCase">If <b>true</b>, ignore case; otherwise, regard case.</param>
        /// <returns>An object of type enumType whose value is represented by value. <b>null</b> if conversion fails.</returns>
        public static T? ParseEnum<T>(string textRepresentation, bool ignoreCase) where T : struct
        {
            if (string.IsNullOrEmpty(textRepresentation))
                return null;

            try
            {
                return (T)Enum.Parse(typeof(T), textRepresentation, ignoreCase);
            }
            catch
            {
                return null;
            }
        }

        private static object ParseEnum(Type enumType, string textRepresentation, bool ignoreCase)
        {
            try
            {
                return Enum.Parse(enumType, textRepresentation, ignoreCase);
            }
            catch
            {
                return null;
            }
        }

        #endregion ParseEnum.

        #region ParseDateTime.

        /// <summary>
        /// Converts the string representation of a date to its <b>DateTime</b> equivalent.
        /// </summary>
        /// <param name="textRepresentation">A string containing a date to convert.</param>
        /// <param name="formatter">An object which contains an <see cref="System.IFormatProvider"/> and
        /// <see cref="DateTimeStyles"/> objects that supply culture-specific formatting information about <b>textRepresentation</b>.</param>
        /// <returns>A date if conversion succeeded; <b>null</b> otherwise.</returns>
        public static DateTime? ParseDateTime(string textRepresentation, IMessageFormatter formatter)
        {
            return ParseDateTime(textRepresentation, formatter.DateStyle, formatter.DateProvider, formatter.DateFormat);
        }

        /// <summary>
        /// Converts the string representation of a date to its <b>DateTime</b> equivalent.
        /// </summary>
        /// <param name="textRepresentation">A string containing a date to convert.</param>
        /// <param name="provider">An <see cref="System.IFormatProvider"/> object that supplies culture-specific
        /// formatting information about <b>textRepresentation</b>.</param>
        /// <returns>A date if conversion succeeded; <b>null</b> otherwise.</returns>
        public static DateTime? ParseDateTime(string textRepresentation, IFormatProvider provider)
        {
            return ParseDateTime(textRepresentation, DateTimeStyles.None, provider, null);
        }

        /// <summary>
        /// Converts the string representation of a date to its <b>DateTime</b> equivalent.
        /// </summary>
        /// <param name="textRepresentation">A string containing a date to convert.</param>
        /// <param name="styles">A bitwise combination of <see cref="System.Globalization.DateTimeStyles"/>
        /// values that indicates the permitted format of textRepresentation. A typical value to specify is
        /// <see cref="System.Globalization.DateTimeStyles.None"/>.</param>
        /// <param name="provider">An <see cref="System.IFormatProvider"/> object that supplies culture-specific
        /// formatting information about <b>textRepresentation</b>.</param>
        /// <returns>A date if conversion succeeded; <b>null</b> otherwise.</returns>
        public static DateTime? ParseDateTime(string textRepresentation, DateTimeStyles styles, IFormatProvider provider)
        {
            return ParseDateTime(textRepresentation, styles, provider, null);
        }

        /// <summary>
        /// Converts the string representation of a date to its <b>DateTime</b> equivalent.
        /// </summary>
        /// <param name="textRepresentation">A string containing a date to convert.</param>
        /// <param name="styles">A bitwise combination of <see cref="System.Globalization.DateTimeStyles"/>
        /// values that indicates the permitted format of textRepresentation. A typical value to specify is
        /// <see cref="System.Globalization.DateTimeStyles.None"/>.</param>
        /// <param name="provider">An <see cref="System.IFormatProvider"/> object that supplies culture-specific
        /// formatting information about <b>textRepresentation</b>.</param>
        /// <param name="format">The expected format of <b>textRepresentation</b>.</param>
        /// <returns>A date if conversion succeeded; <b>null</b> otherwise.</returns>
        public static DateTime? ParseDateTime(string textRepresentation, DateTimeStyles styles, IFormatProvider provider, string format)
        {
            if (string.IsNullOrEmpty(textRepresentation))
                return null;

            textRepresentation = textRepresentation.Trim();
            DateTime date;
            bool isParsed;
            if (format != null)
            {
                isParsed = DateTime.TryParseExact(textRepresentation, format, provider, styles, out date);

                // Retry without exact format.
                if (!isParsed)
                    isParsed = DateTime.TryParse(textRepresentation, provider, styles, out date);
            }
            else
            {
                isParsed = DateTime.TryParse(textRepresentation, provider, styles, out date);
            }

            return (isParsed) ? (DateTime?)date : null;
        }

        #endregion ParseDateTime.

        #region ParseValue.

        /// <summary>
        /// Converts the string to a value of the specified type.
        /// </summary>
        /// <param name="valueType">Type of the value to return.</param>
        /// <param name="textRepresentation">A string containing a value to convert.</param>
        /// <param name="formatter">An object which contains an <see cref="System.IFormatProvider"/> and
        /// <see cref="DateTimeStyles"/> objects that supply culture-specific formatting information about <b>textRepresentation</b>.</param>
        /// <returns>A value if conversion succeeded; <b>null</b> otherwise.</returns>
        public static object ParseValue(Type valueType, string textRepresentation, IMessageFormatter formatter)
        {
            if (valueType == null)
                throw new ArgumentNullException("valueType", "Type of the value must be specified.");
            if (formatter == null)
                throw new ArgumentNullException("formatter", "Formatter must be provided.");

            if (string.IsNullOrEmpty(textRepresentation))
                return null;
            textRepresentation = textRepresentation.Trim();
            if (textRepresentation.Length == 0)
                return null;

            object hiByteCountTypeValue = null;
            if (TypeUtil.IsText(valueType))
                hiByteCountTypeValue = textRepresentation;
            else if (TypeUtil.IsInteger(valueType))
                hiByteCountTypeValue = ParseLong(textRepresentation);
            else if (TypeUtil.IsFloatingPointNumber(valueType))
                hiByteCountTypeValue = ParseDouble(textRepresentation, formatter);
            else if (TypeUtil.IsDate(valueType))
                hiByteCountTypeValue = ParseDateTime(textRepresentation, formatter);
            else if (valueType.IsEnum)
                hiByteCountTypeValue = ParseEnum(valueType, textRepresentation, true);

            // Downgrade to the requested type.
            object requestedTypeValue;
            if (hiByteCountTypeValue != null)
                requestedTypeValue = Convert.ChangeType(hiByteCountTypeValue, valueType);
            else
                requestedTypeValue = null;

            return requestedTypeValue;
        }

        /// <summary>
        /// Converts the string to a value of the specified type.
        /// </summary>
        /// <typeparam name="T">Type of the value to return.</typeparam>
        /// <param name="textRepresentation">A string containing a value to convert.</param>
        /// <param name="formatter">An object which contains an <see cref="System.IFormatProvider"/> and
        /// <see cref="DateTimeStyles"/> objects that supply culture-specific formatting information about <b>textRepresentation</b>.</param>
        /// <returns>A value if conversion succeeded; <b>null</b> otherwise.</returns>
        public static Nullable<T> ParseValue<T>(string textRepresentation, IMessageFormatter formatter)
            where T : struct, IConvertible
        {
            object value = ParseValue(typeof(T), textRepresentation, formatter);
            if (value != null)
                return (T)value;
            else
                return null;
        }

        #endregion ParseValue.

        #region ParseArray.

        /// <summary>
        /// Converts the string to an array of values of the specified type.
        /// </summary>
        /// <param name="elementType">Type of the value to return.</param>
        /// <param name="delimitedElements">A string containing values to convert.</param>
        /// <param name="delimiter">A character which delimites the elements of the array in the string.</param>
        /// <param name="formatter">An object which contains an <see cref="System.IFormatProvider"/> and
        /// <see cref="DateTimeStyles"/> objects that supply culture-specific formatting information about <b>textRepresentation</b>.</param>
        /// <returns>Array which contains the objects of the specified type and nulls for values which couldn't be parsed.</returns>
        public static object[] ParseArray(Type elementType, string delimitedElements, char delimiter, IMessageFormatter formatter)
        {
            string[] txtElements = delimitedElements.Split(delimiter);
            object[] arr = new object[txtElements.Length];
            for (int idxElement = 0; idxElement < arr.Length; idxElement++)
                arr[idxElement] = ParseValue(elementType, txtElements[idxElement], formatter);

            return arr;
        }

        /// <summary>
        /// Converts the string to an array of values of the specified type.
        /// </summary>
        /// <param name="elementType">Type of the value to return.</param>
        /// <param name="delimitedElements">A string containing values to convert.</param>
        /// <param name="delimiter">A string which delimites the elements of the array in the string.</param>
        /// <param name="formatter">An object which contains an <see cref="System.IFormatProvider"/> and
        /// <see cref="DateTimeStyles"/> objects that supply culture-specific formatting information about <b>textRepresentation</b>.</param>
        /// <returns>Array which contains the objects of the specified type and nulls for values which couldn't be parsed.</returns>
        public static object[] ParseArray(Type elementType, string delimitedElements, string delimiter, IMessageFormatter formatter)
        {
            string[] txtElements = delimitedElements.Split(new string[] { delimiter }, StringSplitOptions.None);
            object[] arr = new object[txtElements.Length];
            for (int idxElement = 0; idxElement < arr.Length; idxElement++)
                arr[idxElement] = ParseValue(elementType, txtElements[idxElement], formatter);

            return arr;
        }

        /// <summary>
        /// Converts the string to an array of values of the specified type.
        /// </summary>
        /// <typeparam name="T">Type of the value to return.</typeparam>
        /// <param name="delimitedElements">A string containing values to convert.</param>
        /// <param name="delimiter">A character which delimites the elements of the array in the string.</param>
        /// <param name="formatter">An object which contains an <see cref="System.IFormatProvider"/> and
        /// <see cref="DateTimeStyles"/> objects that supply culture-specific formatting information about <b>textRepresentation</b>.</param>
        /// <returns>Array which contains the objects of the specified type and nulls for values which couldn't be parsed.</returns>
        public static Nullable<T>[] ParseArray<T>(string delimitedElements, char delimiter, IMessageFormatter formatter)
            where T : struct, IConvertible
        {
            object[] arr = ParseArray(typeof(T), delimitedElements, delimiter, formatter);
            T?[] strongTypedArray = new T?[arr.Length];
            arr.CopyTo(strongTypedArray, 0);
            return strongTypedArray;
        }

        /// <summary>
        /// Converts the string to an array of values of the specified type.
        /// </summary>
        /// <typeparam name="T">Type of the value to return.</typeparam>
        /// <param name="delimitedElements">A string containing values to convert.</param>
        /// <param name="delimiter">A character which delimites the elements of the array in the string.</param>
        /// <param name="formatter">An object which contains an <see cref="System.IFormatProvider"/> and
        /// <see cref="DateTimeStyles"/> objects that supply culture-specific formatting information about <b>textRepresentation</b>.</param>
        /// <returns>Array which contains the objects of the specified type and nulls for values which couldn't be parsed.</returns>
        public static Nullable<T>[] ParseArray<T>(string delimitedElements, string delimiter, IMessageFormatter formatter)
            where T : struct, IConvertible
        {
            object[] arr = ParseArray(typeof(T), delimitedElements, delimiter, formatter);
            T?[] strongTypedArray = new T?[arr.Length];
            arr.CopyTo(strongTypedArray, 0);
            return strongTypedArray;
        }

        #endregion ParseArray.

        #region ParseDictionary.

        /// <summary>
        /// Converts a string to a dictionary with keys and values of the specified types.
        /// </summary>
        /// <param name="keyType">The type of the keys in the dictionary.</param>
        /// <param name="valueType">The type of the values in the dictionary.</param>
        /// <param name="delimitedVariables">A string containing varibles (key-value pairs) to convert.</param>
        /// <param name="variableDelimiter">A character which delimites variables in the string.</param>
        /// <param name="keyValueDelimiter">A character which delimites a key from a value in a key-value pair.</param>
        /// <param name="formatter">An object which contains an <see cref="System.IFormatProvider"/> and
        /// <see cref="DateTimeStyles"/> objects that supply culture-specific formatting information about <b>textRepresentation</b>.</param>
        /// <returns>Hashtable which contains the keys and values of the specified types.
        /// Values which couldn't be parsed are represented with <b>null</b> references.</returns>
        public static Hashtable ParseDictionary(Type keyType, Type valueType, string delimitedVariables, char variableDelimiter, char keyValueDelimiter, IMessageFormatter formatter)
        {
            string[] keyValuePairs = delimitedVariables.Split(variableDelimiter);
            Hashtable dictionary = new Hashtable(keyValuePairs.Length);
            foreach (string keyAndValue in keyValuePairs)
            {
                int firstDelimiterOccurrence = keyAndValue.IndexOf(keyValueDelimiter);
                if (firstDelimiterOccurrence < 0)
                    throw new InvalidOperationException("Key-value pair (" + keyAndValue + ") doesn't contain the specified key-value delimiter (" + keyValueDelimiter + ").");

                int keyLen = firstDelimiterOccurrence;
                string keyString = keyAndValue.Substring(0, keyLen);

                const int delimiterLen = 1;
                int valueStart = firstDelimiterOccurrence + delimiterLen;
                string valueString = (valueStart < keyAndValue.Length) ? keyAndValue.Substring(valueStart, keyAndValue.Length - valueStart) : string.Empty;

                object key = ParseValue(keyType, keyString, formatter);
                object value = ParseValue(valueType, valueString, formatter);

                dictionary[key] = value;
            }

            return dictionary;
        }

        /// <summary>
        /// Converts a string to a dictionary with keys and values of the specified types.
        /// </summary>
        /// <param name="keyType">The type of the keys in the dictionary.</param>
        /// <param name="valueType">The type of the values in the dictionary.</param>
        /// <param name="delimitedVariables">A string containing varibles (key-value pairs) to convert.</param>
        /// <param name="variableDelimiter">A string which delimites variables in the string.</param>
        /// <param name="keyValueDelimiter">A string which delimites a key from a value in a key-value pair.</param>
        /// <param name="formatter">An object which contains an <see cref="System.IFormatProvider"/> and
        /// <see cref="DateTimeStyles"/> objects that supply culture-specific formatting information about <b>textRepresentation</b>.</param>
        /// <returns>Hashtable which contains the keys and values of the specified types.
        /// Values which couldn't be parsed are represented with <b>null</b> references.</returns>
        public static Hashtable ParseDictionary(Type keyType, Type valueType, string delimitedVariables, string variableDelimiter, string keyValueDelimiter, IMessageFormatter formatter)
        {
            string[] keyValuePairs = delimitedVariables.Split(new string[] { variableDelimiter }, StringSplitOptions.None);
            Hashtable dictionary = new Hashtable(keyValuePairs.Length);
            foreach (string keyAndValue in keyValuePairs)
            {
                int firstDelimiterOccurrence = keyAndValue.IndexOf(keyValueDelimiter);
                if (firstDelimiterOccurrence < 0)
                    throw new InvalidOperationException("Key-value pair (" + keyAndValue + ") doesn't contain the specified key-value delimiter (" + keyValueDelimiter + ").");

                int keyLen = firstDelimiterOccurrence;
                string keyString = keyAndValue.Substring(0, keyLen);

                int delimiterLen = keyValueDelimiter.Length;
                int valueStart = firstDelimiterOccurrence + delimiterLen;
                string valueString = (valueStart < keyAndValue.Length) ? keyAndValue.Substring(valueStart, keyAndValue.Length - valueStart) : string.Empty;

                object key = ParseValue(keyType, keyString, formatter);
                object value = ParseValue(valueType, valueString, formatter);

                dictionary[key] = value;
            }

            return dictionary;
        }

        /// <summary>
        /// Converts a string to a dictionary with keys and values of the specified types.
        /// </summary>
        /// <typeparam name="TKey">The type of the keys in the dictionary.</typeparam>
        /// <typeparam name="TValue">The type of the values in the dictionary.</typeparam>
        /// <param name="delimitedVariables">A string containing varibles (key-value pairs) to convert.</param>
        /// <param name="variableDelimiter">A character which delimites variables in the string.</param>
        /// <param name="keyValueDelimiter">A character which delimites a key from a value in a key-value pair.</param>
        /// <param name="formatter">An object which contains an <see cref="System.IFormatProvider"/> and
        /// <see cref="DateTimeStyles"/> objects that supply culture-specific formatting information about <b>textRepresentation</b>.</param>
        /// <returns>Dictionary which contains the keys and values of the specified types.
        /// Values which couldn't be parsed are represented with <b>null</b> references.</returns>
        public static Dictionary<TKey, Nullable<TValue>> ParseDictionary<TKey, TValue>(string delimitedVariables, char variableDelimiter, char keyValueDelimiter, IMessageFormatter formatter)
            where TValue : struct, IConvertible
        {
            Hashtable table = ParseDictionary(typeof(TKey), typeof(TValue), delimitedVariables, variableDelimiter, keyValueDelimiter, formatter);
            Dictionary<TKey, TValue?> strongTypedDictionary = new Dictionary<TKey, TValue?>(table.Count);
            foreach (DictionaryEntry keyAndValue in table)
            {
                TKey key = (TKey)keyAndValue.Key;
                TValue? value;
                if (keyAndValue.Value != null)
                    value = (TValue)keyAndValue.Value;
                else
                    value = null;

                strongTypedDictionary[key] = value;
            }

            return strongTypedDictionary;
        }

        /// <summary>
        /// Converts a string to a dictionary with keys and values of the specified types.
        /// </summary>
        /// <typeparam name="TKey">The type of the keys in the dictionary.</typeparam>
        /// <typeparam name="TValue">The type of the values in the dictionary.</typeparam>
        /// <param name="delimitedVariables">A string containing varibles (key-value pairs) to convert.</param>
        /// <param name="variableDelimiter">A string which delimites variables in the string.</param>
        /// <param name="keyValueDelimiter">A string which delimites a key from a value in a key-value pair.</param>
        /// <param name="formatter">An object which contains an <see cref="System.IFormatProvider"/> and
        /// <see cref="DateTimeStyles"/> objects that supply culture-specific formatting information about <b>textRepresentation</b>.</param>
        /// <returns>Dictionary which contains the keys and values of the specified types.
        /// Values which couldn't be parsed are represented with <b>null</b> references.</returns>
        public static Dictionary<TKey, Nullable<TValue>> ParseDictionary<TKey, TValue>(string delimitedVariables, string variableDelimiter, string keyValueDelimiter, IMessageFormatter formatter)
            where TValue : struct, IConvertible
        {
            Hashtable table = ParseDictionary(typeof(TKey), typeof(TValue), delimitedVariables, variableDelimiter, keyValueDelimiter, formatter);
            Dictionary<TKey, TValue?> strongTypedDictionary = new Dictionary<TKey, TValue?>(table.Count);
            foreach (DictionaryEntry keyAndValue in table)
            {
                TKey key = (TKey)keyAndValue.Key;
                TValue? value;
                if (keyAndValue.Value != null)
                    value = (TValue)keyAndValue.Value;
                else
                    value = null;

                strongTypedDictionary[key] = value;
            }

            return strongTypedDictionary;
        }

        #endregion ParseDictionary.

        #region ParseValidValues.

        /// <summary>
        /// Converts the string to an array of values of the specified type.
        /// </summary>
        /// <typeparam name="T">Type of the value to return.</typeparam>
        /// <param name="delimitedElements">A string containing values to convert.</param>
        /// <param name="delimiter">A character which delimites the elements of the array in the string.</param>
        /// <param name="formatter">An object which contains an <see cref="System.IFormatProvider"/> and
        /// <see cref="DateTimeStyles"/> objects that supply culture-specific formatting information about <b>textRepresentation</b>.</param>
        /// <returns>Array which contains only values which were succesfully parsed.</returns>
        public static T[] ParseValidValues<T>(string delimitedElements, char delimiter, IMessageFormatter formatter)
            where T : struct, IConvertible
        {
            T?[] nullableValues = ParseArray<T>(delimitedElements, delimiter, formatter);
            return GetElementsWithValues<T>(nullableValues);
        }

        /// <summary>
        /// Converts the string to an array of values of the specified type.
        /// </summary>
        /// <typeparam name="T">Type of the value to return.</typeparam>
        /// <param name="delimitedElements">A string containing values to convert.</param>
        /// <param name="delimiter">A character which delimites the elements of the array in the string.</param>
        /// <param name="formatter">An object which contains an <see cref="System.IFormatProvider"/> and
        /// <see cref="DateTimeStyles"/> objects that supply culture-specific formatting information about <b>textRepresentation</b>.</param>
        /// <returns>Array which contains only values which were succesfully parsed.</returns>
        public static T[] ParseValidValues<T>(string delimitedElements, string delimiter, IMessageFormatter formatter)
            where T : struct, IConvertible
        {
            T?[] nullableValues = ParseArray<T>(delimitedElements, delimiter, formatter);
            return GetElementsWithValues<T>(nullableValues);
        }

        private static T[] GetElementsWithValues<T>(T?[] nullableValues)
            where T : struct
        {
            List<T> values = new List<T>();
            foreach (T? val in nullableValues)
            {
                if (val.HasValue)
                    values.Add(val.Value);
            }

            return values.ToArray();
        }

        #endregion ParseValidValues.
    }

    /// <summary>
    /// Provides methods which classify the basic .NET types.
    /// </summary>
    public static class TypeUtil
    {
        #region IsInteger.

        /// <summary>
        /// Indicates whether the given type is an integer number (Int32, Byte, Long etc.).
        /// </summary>
        /// <param name="t">Type to be tested.</param>
        /// <returns>True if a given type is an integral type; false otherwise.</returns>
        public static bool IsInteger(Type t)
        {
            if (t == typeof(Int32) || t == typeof(Byte) || t == typeof(Int16) || t == typeof(Int64) || t == typeof(SByte) || t == typeof(UInt16) || t == typeof(UInt32) || t == typeof(Int64))
                return true;
            else
                return false;
        }

        #endregion IsInteger.

        #region IsFloatingPointNumber.

        /// <summary>
        /// Indicates wheter the given type is a floating point number (Single, Double, Decimal).
        /// </summary>
        /// <param name="t">Type to be tested.</param>
        /// <returns>True if a given type is an integral type; false otherwise.</returns>
        public static bool IsFloatingPointNumber(Type t)
        {
            if (t == typeof(Single) || t == typeof(Double) || t == typeof(Decimal))
                return true;
            else
                return false;
        }

        #endregion IsFloatingPointNumber.

        #region IsNumber.

        /// <summary>
        /// Indicates whether the given type is a number (integer or real number).
        /// </summary>
        /// <param name="t">Type to be tested.</param>
        /// <returns>True if a given type is an integral type; false otherwise.</returns>
        public static bool IsNumber(Type t)
        {
            if (IsFloatingPointNumber(t) || IsInteger(t))
                return true;
            else
                return false;
        }

        #endregion IsNumber.

        #region IsDate.

        /// <summary>
        /// Indicates whether the given type is a date type.
        /// </summary>
        /// <param name="t">Type to be tested.</param>
        /// <returns>True if a given type is an integral type; false otherwise.</returns>
        public static bool IsDate(Type t)
        {
            if (t == typeof(DateTime))
                return true;
            else
                return false;
        }

        #endregion IsDate.

        #region IsText.

        /// <summary>
        /// Indicates whether the given type is textual (String, Char, Char[]).
        /// </summary>
        /// <param name="t">Type to be tested.</param>
        /// <returns>True if a given type is an integral type; false otherwise.</returns>
        public static bool IsText(Type t)
        {
            if (t == typeof(String) || t == typeof(Char) || t == typeof(Char[]))
                return true;
            else
                return false;
        }

        #endregion IsText.
    }

    /// <summary>
    /// Provides common operations for array and list manipulation (conversions, sets...).
    /// </summary>
    public static class ArrayUtil
    {
        #region Conversions.

        /// <summary>
        /// Converts an ArrayList to an array of objects.
        /// </summary>
        /// <param name="list">Source list.</param>
        /// <returns>An array of objects which contains the same objects (same references) as the source list.</returns>
        public static object[] ToObjectArray(IList list)
        {
            object[] array = new object[list.Count];
            for (int i = 0; i < list.Count; i++)
                array[i] = list[i];

            return array;
        }

        /// <summary>
        /// Converts an ArrayList to an array of integers.
        /// </summary>
        /// <param name="list">Source list.</param>
        /// <returns>An array of integers which contains the same values (not references) as the source list.</returns>
        public static int[] ToIntArray(IList list)
        {
            int[] array = new int[list.Count];
            for (int i = 0; i < list.Count; i++)
                array[i] = (int)list[i];

            return array;
        }

        private static ArrayList ToArrayList(IEnumerable vector)
        {
            ArrayList list = new ArrayList();
            foreach (object o in vector)
                list.Add(o);

            return list;
        }

        /// <summary>
        /// Converts a list to array.
        /// </summary>
        /// <typeparam name="T">Type of objects contained in the list.</typeparam>
        /// <param name="list">A list of objects.</param>
        /// <returns>Array containg the same objects as the input list.</returns>
        public static T[] ToArray<T>(IList list)
        {
            T[] array = new T[list.Count];
            list.CopyTo(array, 0);
            return array;
        }

        /// <summary>
        /// Converts a collection to array.
        /// </summary>
        /// <typeparam name="T">Type of objects contained in the list.</typeparam>
        /// <param name="collection">A collection of objects.</param>
        /// <returns>Array containg the same objects as the input collection.</returns>
        public static T[] ToArray<T>(IEnumerable collection)
        {
            IList list = (collection is IList) ? (IList)collection : ArrayUtil.ToArrayList(collection);
            return ToArray<T>(list);
        }

        /// <summary>
        /// Creates an array that contains the values in the specified property.
        /// </summary>
        /// <typeparam name="T">Type of objects contained in the output array.</typeparam>
        /// <param name="list">A list of objects that have the specified property.</param>
        /// <param name="propertyName">Property that holds the numbers which are to be coppied to array.</param>
        /// <returns>Array.</returns>
        public static T[] ToArray<T>(IList list, string propertyName)
        {
            T[] array = new T[list.Count];
            PropertyInfo property = null;
            for (int i = 0; i < list.Count; i++)
            {
                object listElement = list[i];
                if (property == null)
                    property = listElement.GetType().GetProperty(propertyName);

                array[i] = (T)property.GetValue(listElement, null);
            }

            return array;
        }

        /// <summary>
        /// Creates an array that contains the values in the specified property.
        /// </summary>
        /// <typeparam name="T">Type of objects contained in the output array.</typeparam>
        /// <param name="collection">A collection of objects that have the specified property.</param>
        /// <param name="propertyName">Property that holds the numbers which are to be coppied to array.</param>
        /// <returns>Array.</returns>
        public static T[] ToArray<T>(IEnumerable collection, string propertyName)
        {
            IList list = (collection is IList) ? (IList)collection : ArrayUtil.ToArrayList(collection);
            return ToArray<T>(list, propertyName);
        }

        /// <summary>
        /// Creates an array that contains the values returned by the specified getter.
        /// </summary>
        /// <typeparam name="TProperty">Type of objects contained in the output array.</typeparam>
        /// <typeparam name="TElement">Type of elements contained in the collection.</typeparam>
        /// <param name="list">A list of objects that have the specified property.</param>
        /// <param name="getValue">A delegate to a method which returns values for output array.</param>
        /// <returns>Array.</returns>
        public static TProperty[] ToArray<TProperty, TElement>(ICollection list, Delegates.Function<TProperty, TElement> getValue)
        {
            TProperty[] array = new TProperty[list.Count];
            int idxElement = 0;
            foreach (TElement el in list)
            {
                array[idxElement] = getValue(el);
                idxElement++;
            }

            return array;
        }

        /// <summary>
        /// Creates an array that contains the values returned by the specified getter.
        /// </summary>
        /// <typeparam name="TProperty">Type of objects contained in the output array.</typeparam>
        /// <typeparam name="TElement">Type of elements contained in the collection.</typeparam>
        /// <param name="collection">A collection of objects that have the specified property.</param>
        /// <param name="getValue">A delegate to a method which returns values for output array.</param>
        /// <returns>Array.</returns>
        public static TProperty[] ToArray<TProperty, TElement>(IEnumerable collection, Delegates.Function<TProperty, TElement> getValue)
        {
            int size = 0;
            foreach (object el in collection)
                size++;

            TProperty[] array = new TProperty[size];
            int idxElement = 0;
            foreach (TElement el in collection)
            {
                array[idxElement] = getValue(el);
                idxElement++;
            }

            return array;
        }

        /// <summary>
        /// Converts all objects from the source collection and adds them to the new list.
        /// </summary>
        /// <typeparam name="TList">Type of the list which is returned from the method.</typeparam>
        /// <typeparam name="TInputElement">Type of elements contained in the source list.</typeparam>
        /// <typeparam name="TOutElement">Type of elements contained in the output list.</typeparam>
        /// <param name="collection">Source list.</param>
        /// <param name="conversion">A delegate which converts an input to output element.</param>
        /// <returns>A list which contains converted elements.</returns>
        public static TList Convert<TList, TInputElement, TOutElement>(IEnumerable collection, Delegates.Function<TOutElement, TInputElement> conversion)
            where TList : IList, new()
        {
            TList outList = new TList();
            foreach (TInputElement inElement in collection)
            {
                TOutElement outElement = conversion(inElement);
                outList.Add(outElement);
            }

            return outList;
        }

        /// <summary>
        /// Converts all objects in the list.
        /// </summary>
        /// <typeparam name="TInputElement">Type of elements contained in the source list.</typeparam>
        /// <typeparam name="TOutElement">Type of elements contained in the output list.</typeparam>
        /// <param name="list">List whose elements are to be converted.</param>
        /// <param name="conversion">A delegate which converts an input to output element.</param>
        public static void ConvertElements<TInputElement, TOutElement>(IList list, Delegates.Function<TOutElement, TInputElement> conversion)
        {
            for (int idx = 0; idx < list.Count; idx++)
            {
                TInputElement inElement = (TInputElement)list[idx];
                TOutElement outElement = conversion(inElement);
                list[idx] = outElement;
            }
        }

        #endregion Conversions.

        #region Object filtering, indexes.

        public static void Shuffle<T>(this IList<T> list)
        {
            Random rng = new Random();
            int n = list.Count;
            while (n > 1)
            {
                n--;
                int k = rng.Next(n + 1);
                T value = list[k];
                list[k] = list[n];
                list[n] = value;
            }
        }

        /// <summary>
        /// Returns zero-based index of an object with the specified key.
        /// </summary>
        /// <typeparam name="TKey">Type of the values in the key property.</typeparam>
        /// <param name="objects">A list or an array of objects.</param>
        /// <param name="keyPropertyName">Name of the property that contains key values.</param>
        /// <param name="key">Key value of object that is to be found in the source list.</param>
        /// <returns>Index of the object; -1 if not found.</returns>
        public static int IndexOf<TKey>(IEnumerable objects, string keyPropertyName, TKey key)
            where TKey : IEquatable<TKey>
        {
            PropertyInfo keyProperty = null;
            int index = 0;
            foreach (object obj in objects)
            {
                if (keyProperty == null)
                    keyProperty = obj.GetType().GetProperty(keyPropertyName);

                TKey currObjKey = (TKey)keyProperty.GetValue(obj, null);
                bool isMatch = currObjKey.Equals(key);
                if (isMatch)
                    return index;

                index++;
            }

            return -1;
        }

        /// <summary>
        /// Returns zero-based index of a first occurance of object which matches the specified criteria.
        /// </summary>
        /// <typeparam name="TElement">Type of elements contained in the collection.</typeparam>
        /// <param name="collection">A collection.</param>
        /// <param name="match">The Predicate(TElement) delegate that defines the conditions of the elements to search for.</param>
        /// <returns>Index of the element; -1 if not found.</returns>
        public static int IndexOf<TElement>(IEnumerable collection, Predicate<TElement> match)
        {
            int currIndex = 0;
            foreach (TElement element in collection)
            {
                if (match(element))
                    return currIndex;

                currIndex++;
            }

            return -1;
        }

        /// <summary>
        /// Searches for the specified object and returns the zero-based index of the first occurrence within the entire collection.
        /// </summary>
        /// <param name="collection">A collection.</param>
        /// <param name="item">The object to locate in the collection. The value can be <b>null</b> for reference types.</param>
        /// <returns>The zero-based index of the first occurrence of item within the entire collection, if found; otherwise, –1.</returns>
        public static int IndexOf(IEnumerable collection, object item)
        {
            int currIndex = 0;
            foreach (object currItem in collection)
            {
                if (item == currItem)
                    return currIndex;

                currIndex++;
            }

            return -1;
        }

        /// <summary>
        /// Removes list items at the specified indexes.
        /// </summary>
        /// <param name="list">A list form which items are to be removed.</param>
        /// <param name="indexes">The zero-based indexes of items to remove.</param>
        public static void RemoveAt(IList list, params int[] indexes)
        {
            if (ArrayUtil.IsNullOrEmpty(indexes))
                return;

            int[] itemsToRemove = new int[indexes.Length];
            indexes.CopyTo(itemsToRemove, 0);
            Array.Sort<int>(itemsToRemove);
            for (int idxReversed = itemsToRemove.Length - 1; idxReversed >= 0; idxReversed--)
                list.RemoveAt(itemsToRemove[idxReversed]);
        }

        #endregion Object filtering, indexes.

        #region Predicates.

        /// <summary>
        /// Determines whether the collection contains elements that match the conditions defined by the specified predicate.
        /// </summary>
        /// <typeparam name="TElement">Type of elements contained in the collection.</typeparam>
        /// <param name="collection">A collection.</param>
        /// <param name="match">The Predicate(TElement) delegate that defines the conditions of the elements to search for.</param>
        /// <returns>true if the collection contains one or more elements that match the conditions defined by the specified predicate; otherwise, false.</returns>
        public static bool Exists<TElement>(IEnumerable collection, Predicate<TElement> match)
        {
            foreach (TElement obj in collection)
            {
                if (match(obj))
                    return true;
            }

            return false;
        }

        /// <summary>
        /// Searches for an element that matches the conditions defined by the specified predicate, and returns the first occurrence within the entire collection.
        /// </summary>
        /// <typeparam name="TElement">Type of elements contained in the collection.</typeparam>
        /// <param name="collection">A collection.</param>
        /// <param name="match">The Predicate(TElement) delegate that defines the conditions of the elements to search for.</param>
        /// <returns>The first element that matches the conditions defined by the specified predicate, if found; otherwise, the default value for type TElement.</returns>
        public static TElement Find<TElement>(IEnumerable collection, Predicate<TElement> match)
        {
            foreach (TElement obj in collection)
            {
                if (match(obj))
                    return obj;
            }

            return default(TElement);
        }

        /// <summary>
        /// Retrieves all the elements that match the conditions defined by the specified predicate.
        /// </summary>
        /// <typeparam name="TList">Type of the list which is returned from the method.</typeparam>
        /// <typeparam name="TElement">Type of elements contained in the collection.</typeparam>
        /// <param name="collection">A collection.</param>
        /// <param name="match">The Predicate(TElement) delegate that defines the conditions of the elements to search for.</param>
        /// <returns>A list containing all the elements that match the conditions defined by the specified predicate, if found; otherwise, an empty list.</returns>
        public static TList FindAll<TList, TElement>(IEnumerable collection, Predicate<TElement> match)
            where TList : IList, new()
        {
            TList matches = new TList();
            foreach (TElement obj in collection)
            {
                if (match(obj))
                    matches.Add(obj);
            }

            return matches;
        }

        /// <summary>
        /// Searches for an element that matches the conditions defined by the specified predicate, and returns the zero-based index of the first occurrence within the entire collection.
        /// </summary>
        /// <typeparam name="TElement">Type of elements contained in the collection.</typeparam>
        /// <param name="collection">A collection.</param>
        /// <param name="match">The Predicate(TElement) delegate that defines the conditions of the elements to search for.</param>
        /// <returns>The zero-based index of the first occurrence of an element that matches the conditions defined by match, if found; otherwise, –1.</returns>
        public static int FindIndex<TElement>(IEnumerable collection, Predicate<TElement> match)
        {
            int index = 0;
            foreach (TElement obj in collection)
            {
                if (match(obj))
                    return index;

                index++;
            }

            return -1;
        }

        /// <summary>
        /// Searches for an element that matches the conditions defined by the specified predicate, and returns the zero-based index of the first occurrence within the range of elements in the collection that extends from the specified index to the last element.
        /// </summary>
        /// <typeparam name="TElement">Type of elements contained in the collection.</typeparam>
        /// <param name="collection">A collection.</param>
        /// <param name="startIndex">The zero-based starting index of the search.</param>
        /// <param name="match">The Predicate(TElement) delegate that defines the conditions of the elements to search for.</param>
        /// <returns>The zero-based index of the first occurrence of an element that matches the conditions defined by match, if found; otherwise, –1.</returns>
        public static int FindIndex<TElement>(IEnumerable collection, int startIndex, Predicate<TElement> match)
        {
            int index = 0;
            foreach (TElement obj in collection)
            {
                bool isMatch = (index >= startIndex) && match(obj);
                if (isMatch)
                    return index;

                index++;
            }

            return -1;
        }

        /// <summary>
        /// Searches for an element that matches the conditions defined by the specified predicate, and returns the zero-based index of the first occurrence within the range of elements in the array that extends from the specified index to the last element.
        /// </summary>
        /// <typeparam name="TElement">Type of elements contained in the array.</typeparam>
        /// <param name="array">An array.</param>
        /// <param name="startIndex">The zero-based starting index of the search.</param>
        /// <param name="match">The Predicate(TElement) delegate that defines the conditions of the elements to search for.</param>
        /// <returns>The zero-based index of the first occurrence of an element that matches the conditions defined by match, if found; otherwise, –1.</returns>
        public static int FindIndex<TElement>(Array array, int startIndex, Predicate<TElement> match)
        {
            for (int index = startIndex; index < array.Length; index++)
            {
                TElement obj = (TElement)array.GetValue(index);
                if (match(obj))
                    return index;
            }

            return -1;
        }

        /// <summary>
        /// Searches for an element that matches the conditions defined by the specified predicate, and returns the zero-based index of the first occurrence within the range of elements in the list that extends from the specified index to the last element.
        /// </summary>
        /// <typeparam name="TElement">Type of elements contained in the list.</typeparam>
        /// <param name="list">A list.</param>
        /// <param name="startIndex">The zero-based starting index of the search.</param>
        /// <param name="match">The Predicate(TElement) delegate that defines the conditions of the elements to search for.</param>
        /// <returns>The zero-based index of the first occurrence of an element that matches the conditions defined by match, if found; otherwise, –1.</returns>
        public static int FindIndex<TElement>(IList list, int startIndex, Predicate<TElement> match)
        {
            for (int index = startIndex; index < list.Count; index++)
            {
                TElement obj = (TElement)list[index];
                if (match(obj))
                    return index;
            }

            return -1;
        }

        /// <summary>
        /// Searches for an element that matches the conditions defined by the specified predicate, and returns the last occurrence within the entire collection.
        /// </summary>
        /// <typeparam name="TElement">Type of elements contained in the collection.</typeparam>
        /// <param name="collection">A collection.</param>
        /// <param name="match">The Predicate(TElement) delegate that defines the conditions of the elements to search for.</param>
        /// <returns>The last element that matches the conditions defined by the specified predicate, if found; otherwise, the default value for type TElement.</returns>
        public static TElement FindLast<TElement>(IEnumerable collection, Predicate<TElement> match)
        {
            TElement lastMatch = default(TElement);
            foreach (TElement obj in collection)
            {
                if (match(obj))
                    lastMatch = obj;
            }

            return lastMatch;
        }

        /// <summary>
        /// Searches for an element that matches the conditions defined by the specified predicate, and returns the last occurrence within the entire array.
        /// </summary>
        /// <typeparam name="TElement">Type of elements contained in the array.</typeparam>
        /// <param name="array">An array.</param>
        /// <param name="match">The Predicate(TElement) delegate that defines the conditions of the elements to search for.</param>
        /// <returns>The last element that matches the conditions defined by the specified predicate, if found; otherwise, the default value for type TElement.</returns>
        public static TElement FindLast<TElement>(Array array, Predicate<TElement> match)
        {
            for (int descIndex = array.Length - 1; descIndex >= 0; descIndex--)
            {
                TElement obj = (TElement)array.GetValue(descIndex);
                if (match(obj))
                    return obj;
            }

            return default(TElement);
        }

        /// <summary>
        /// Searches for an element that matches the conditions defined by the specified predicate, and returns the last occurrence within the entire list.
        /// </summary>
        /// <typeparam name="TElement">Type of elements contained in the list.</typeparam>
        /// <param name="list">A list.</param>
        /// <param name="match">The Predicate(TElement) delegate that defines the conditions of the elements to search for.</param>
        /// <returns>The last element that matches the conditions defined by the specified predicate, if found; otherwise, the default value for type TElement.</returns>
        public static TElement FindLast<TElement>(IList list, Predicate<TElement> match)
        {
            for (int descIndex = list.Count - 1; descIndex >= 0; descIndex--)
            {
                TElement obj = (TElement)list[descIndex];
                if (match(obj))
                    return obj;
            }

            return default(TElement);
        }

        /// <summary>
        /// Searches for an element that matches the conditions defined by the specified predicate, and returns the zero-based index of the last occurrence within the entire collection.
        /// </summary>
        /// <typeparam name="TElement">Type of elements contained in the collection.</typeparam>
        /// <param name="collection">A collection.</param>
        /// <param name="match">The Predicate(TElement) delegate that defines the conditions of the elements to search for.</param>
        /// <returns>The zero-based index of the last occurrence of an element that matches the conditions defined by match, if found; otherwise, –1.</returns>
        public static int FindLastIndex<TElement>(IEnumerable collection, Predicate<TElement> match)
        {
            int index = 0;
            int lastMatch = -1;
            foreach (TElement obj in collection)
            {
                if (match(obj))
                    lastMatch = index;

                index++;
            }

            return lastMatch;
        }

        /// <summary>
        /// Searches for an element that matches the conditions defined by the specified predicate, and returns the zero-based index of the last occurrence within the entire array.
        /// </summary>
        /// <typeparam name="TElement">Type of elements contained in the array.</typeparam>
        /// <param name="array">An array.</param>
        /// <param name="match">The Predicate(TElement) delegate that defines the conditions of the elements to search for.</param>
        /// <returns>The zero-based index of the last occurrence of an element that matches the conditions defined by match, if found; otherwise, –1.</returns>
        public static int FindLastIndex<TElement>(Array array, Predicate<TElement> match)
        {
            for (int descIndex = array.Length - 1; descIndex >= 0; descIndex--)
            {
                TElement obj = (TElement)array.GetValue(descIndex);
                if (match(obj))
                    return descIndex;
            }

            return -1;
        }

        /// <summary>
        /// Searches for an element that matches the conditions defined by the specified predicate, and returns the zero-based index of the last occurrence within the entire list.
        /// </summary>
        /// <typeparam name="TElement">Type of elements contained in the list.</typeparam>
        /// <param name="list">A list.</param>
        /// <param name="match">The Predicate(TElement) delegate that defines the conditions of the elements to search for.</param>
        /// <returns>The zero-based index of the last occurrence of an element that matches the conditions defined by match, if found; otherwise, –1.</returns>
        public static int FindLastIndex<TElement>(IList list, Predicate<TElement> match)
        {
            for (int descIndex = list.Count - 1; descIndex >= 0; descIndex--)
            {
                TElement obj = (TElement)list[descIndex];
                if (match(obj))
                    return descIndex;
            }

            return -1;
        }

        /// <summary>
        /// Removes the all the elements that match the conditions defined by the specified predicate.
        /// </summary>
        /// <typeparam name="TElement">Type of elements contained in the list.</typeparam>
        /// <param name="list">A list.</param>
        /// <param name="match">The Predicate(TElement) delegate that defines the conditions of the elements to search for.</param>
        /// <returns>The number of elements removed from the list.</returns>
        public static int RemoveAll<TElement>(IList list, Predicate<TElement> match)
        {
            List<int> indexesToRemove = new List<int>();
            for (int idxOfTested = 0; idxOfTested < list.Count; idxOfTested++)
            {
                TElement obj = (TElement)list[idxOfTested];
                if (match(obj))
                    indexesToRemove.Add(idxOfTested);
            }

            if (indexesToRemove.Count > 0)
                RemoveAt(list, indexesToRemove.ToArray());

            return indexesToRemove.Count;
        }

        /// <summary>
        /// Determines whether every element in the collection matches the conditions defined by the specified predicate.
        /// </summary>
        /// <typeparam name="TElement">Type of elements contained in the list.</typeparam>
        /// <param name="collection">A collection.</param>
        /// <param name="match">The Predicate(TElement) delegate that defines the conditions to check against the elements.</param>
        /// <returns>true if every element in the collection matches the conditions defined by the specified predicate; otherwise, false. If the list has no elements, the return value is true.</returns>
        public static bool TrueForAll<TElement>(IEnumerable collection, Predicate<TElement> match)
        {
            foreach (TElement obj in collection)
            {
                if (!match(obj))
                    return false;
            }

            return true;
        }

        #endregion Predicates.

        #region IsNullOrEmpty.

        /// <summary>
        /// Checks whether the specified array is a null reference or an empty array.
        /// </summary>
        /// <param name="array">Array to check.</param>
        /// <returns><b>true</b> if the provided array is <b>null</b> or empty; otherwise, false.</returns>
        public static bool IsNullOrEmpty(Array array)
        {
            bool isNullOrEmtpy = (array == null) || (array.Length == 0);
            return isNullOrEmtpy;
        }

        /// <summary>
        /// Checks whether the specified collection is a null reference or an empty collection.
        /// </summary>
        /// <param name="collection">Collection to check.</param>
        /// <returns><b>true</b> if the provided collection is <b>null</b> or empty; otherwise, false.</returns>
        public static bool IsNullOrEmpty(ICollection collection)
        {
            bool isNullOrEmtpy = (collection == null) || (collection.Count == 0);
            return isNullOrEmtpy;
        }

        /// <summary>
        /// Checks whether the specified collection is a null reference or an empty collection.
        /// </summary>
        /// <param name="collection">Collection to check.</param>
        /// <returns><b>true</b> if the provided collection is <b>null</b> or empty; otherwise, false.</returns>
        public static bool IsNullOrEmpty(IEnumerable collection)
        {
            if (collection == null)
                return true;

            IEnumerator enumerator = collection.GetEnumerator();
            bool isEmpty = !enumerator.MoveNext();
            return isEmpty;
        }

        #endregion IsNullOrEmpty.

        #region Get/set first/last element.

        /// <summary>
        /// Returns last element in the list.
        /// </summary>
        /// <typeparam name="TElement">Type of elements contained in the input list.</typeparam>
        /// <param name="list">A list of objects.</param>
        /// <returns>Last element or null if the list is empty or null.</returns>
        public static TElement? GetLastValue<TElement>(IList list)
            where TElement : struct
        {
            TElement? lastElement;
            if (ArrayUtil.IsNullOrEmpty(list))
                lastElement = null;
            else
                lastElement = (TElement)list[list.Count - 1];

            return lastElement;
        }

        /// <summary>
        /// Returns last element in the array.
        /// </summary>
        /// <typeparam name="TElement">Type of elements contained in the input array.</typeparam>
        /// <param name="array">An array of objects.</param>
        /// <returns>Last element or null if the array is empty or null.</returns>
        public static TElement? GetLastValue<TElement>(Array array)
            where TElement : struct
        {
            TElement? lastElement;
            if (ArrayUtil.IsNullOrEmpty(array))
                lastElement = null;
            else
                lastElement = (TElement)array.GetValue(array.Length - 1);

            return lastElement;
        }

        /// <summary>
        /// Returns last element in the collection.
        /// </summary>
        /// <typeparam name="TElement">Type of elements contained in the input collection.</typeparam>
        /// <param name="collection">A collection of objects.</param>
        /// <returns>Last element or null if the collection is empty or null.</returns>
        public static TElement? GetLastValue<TElement>(IEnumerable collection)
            where TElement : struct
        {
            TElement? lastElement = null;
            if (collection != null)
            {
                foreach (TElement element in collection)
                    lastElement = element;
            }

            return lastElement;
        }

        /// <summary>
        /// Returns last element in the list.
        /// </summary>
        /// <typeparam name="TElement">Type of elements contained in the input list.</typeparam>
        /// <param name="list">A list of objects.</param>
        /// <returns>Last element or null if the list is empty or null.</returns>
        public static TElement GetLastObject<TElement>(IList list)
            where TElement : class
        {
            TElement lastElement;
            if (ArrayUtil.IsNullOrEmpty(list))
                lastElement = null;
            else
                lastElement = (TElement)list[list.Count - 1];

            return lastElement;
        }

        /// <summary>
        /// Returns last element in the array.
        /// </summary>
        /// <typeparam name="TElement">Type of elements contained in the input array.</typeparam>
        /// <param name="array">An array of objects.</param>
        /// <returns>Last element or null if the array is empty or null.</returns>
        public static TElement GetLastObject<TElement>(Array array)
            where TElement : class
        {
            TElement lastElement;
            if (ArrayUtil.IsNullOrEmpty(array))
                lastElement = null;
            else
                lastElement = (TElement)array.GetValue(array.Length - 1);

            return lastElement;
        }

        /// <summary>
        /// Returns last element in the collection.
        /// </summary>
        /// <typeparam name="TElement">Type of elements contained in the input collection.</typeparam>
        /// <param name="collection">A collection of objects.</param>
        /// <returns>Last element or null if the collection is empty or null.</returns>
        public static TElement GetLastObject<TElement>(IEnumerable collection)
            where TElement : class
        {
            TElement lastElement = null;
            if (collection != null)
            {
                foreach (TElement element in collection)
                    lastElement = element;
            }

            return lastElement;
        }

        /// <summary>
        /// Returns first element in the list.
        /// </summary>
        /// <typeparam name="TElement">Type of elements contained in the input list.</typeparam>
        /// <param name="list">A list of objects.</param>
        /// <returns>First element or null if the list is empty or null.</returns>
        public static TElement? GetFirstValue<TElement>(IList list)
            where TElement : struct
        {
            TElement? firstElement;
            if (ArrayUtil.IsNullOrEmpty(list))
                firstElement = null;
            else
                firstElement = (TElement)list[0];

            return firstElement;
        }

        /// <summary>
        /// Returns first element in the list.
        /// </summary>
        /// <typeparam name="TElement">Type of elements contained in the input list.</typeparam>
        /// <param name="array">An array of objects.</param>
        /// <returns>First element or null if the list is empty or null.</returns>
        public static TElement? GetFirstValue<TElement>(Array array)
            where TElement : struct
        {
            TElement? firstElement;
            if (ArrayUtil.IsNullOrEmpty(array))
                firstElement = null;
            else
                firstElement = (TElement)array.GetValue(0);

            return firstElement;
        }

        /// <summary>
        /// Returns first element in the list.
        /// </summary>
        /// <typeparam name="TElement">Type of elements contained in the input list.</typeparam>
        /// <param name="collection">A collection of objects.</param>
        /// <returns>First element or null if the list is empty or null.</returns>
        public static TElement? GetFirstValue<TElement>(IEnumerable collection)
            where TElement : struct
        {
            TElement? firstElement = null;
            if (collection != null)
            {
                foreach (TElement element in collection)
                {
                    firstElement = element;
                    break;
                }
            }

            return firstElement;
        }

        /// <summary>
        /// Returns first element in the list.
        /// </summary>
        /// <typeparam name="TElement">Type of elements contained in the input list.</typeparam>
        /// <param name="list">A list of objects.</param>
        /// <returns>First element or null if the list is empty or null.</returns>
        public static TElement GetFirstObject<TElement>(IList list)
            where TElement : class
        {
            TElement firstElement;
            if (ArrayUtil.IsNullOrEmpty(list))
                firstElement = null;
            else
                firstElement = (TElement)list[0];

            return firstElement;
        }

        /// <summary>
        /// Returns first element in the list.
        /// </summary>
        /// <typeparam name="TElement">Type of elements contained in the input list.</typeparam>
        /// <param name="array">An array of objects.</param>
        /// <returns>First element or null if the list is empty or null.</returns>
        public static TElement GetFirstObject<TElement>(Array array)
            where TElement : class
        {
            TElement firstElement;
            if (ArrayUtil.IsNullOrEmpty(array))
                firstElement = null;
            else
                firstElement = (TElement)array.GetValue(0);

            return firstElement;
        }

        /// <summary>
        /// Returns first element in the list.
        /// </summary>
        /// <typeparam name="TElement">Type of elements contained in the input list.</typeparam>
        /// <param name="collection">A collection of objects.</param>
        /// <returns>First element or null if the list is empty or null.</returns>
        public static TElement GetFirstObject<TElement>(IEnumerable collection)
            where TElement : class
        {
            TElement firstElement = null;
            if (collection != null)
            {
                foreach (TElement element in collection)
                {
                    firstElement = element;
                    break;
                }
            }

            return firstElement;
        }

        /// <summary>
        /// Sets first element of the list.
        /// </summary>
        /// <param name="list">A list of objects. If empty, the element will be added.</param>
        /// <param name="element">Object to set.</param>
        public static void SetFirstElement(IList list, object element)
        {
            if (list.Count > 0)
                list[0] = element;
            else
                list.Add(element);
        }

        /// <summary>
        /// Sets first element of the list.
        /// </summary>
        /// <typeparam name="TElement">Type of elements contained in the input list.</typeparam>
        /// <param name="list">A list of objects. If empty, the element will be added.</param>
        /// <param name="element">Object to set.</param>
        public static void SetFirstElement<TElement>(IList<TElement> list, TElement element)
        {
            if (list.Count > 0)
                list[0] = element;
            else
                list.Add(element);
        }

        #endregion Get/set first/last element.

        #region Sets.

        /// <summary>
        /// Creates an array of objects with values in the given property.
        /// </summary>
        /// <param name="list">A list of objects that have the specified property.</param>
        /// <param name="property">Property that holds the values which are to be coppied to array.</param>
        /// <returns>Array of objects.</returns>
        public static object[] ToObjectArray(IList list, string property)
        {
            object[] array = new object[list.Count];
            for (int i = 0; i < list.Count; i++)
            {
                object val = ReflectionUtil.GetPublicPropertyValue(list[i], property);
                array[i] = val;
            }

            return array;
        }

        /// <summary>
        /// Creates an array of integers with values in the given property.
        /// </summary>
        /// <param name="list">A list of objects that have the specified property.</param>
        /// <param name="property">Property that holds the numbers which are to be coppied to array.</param>
        /// <returns>Array of integers.</returns>
        public static int[] ToIntArray(IList list, string property)
        {
            int[] array = new int[list.Count];
            for (int i = 0; i < list.Count; i++)
            {
                int val = (int)ReflectionUtil.GetPublicPropertyValue(list[i], property);
                array[i] = val;
            }

            return array;
        }

        /// <summary>
        /// Gets all object that don't have the specified keys.
        /// </summary>
        /// <param name="allObjects">Source list.</param>
        /// <param name="keyProperty">Name of the property that contains key values.</param>
        /// <param name="excludedKeyValues">Key values of object that will <b>not</b> be added to output list.</param>
        /// <returns>A list of objects without the specified keys.</returns>
        public static ArrayList GetObjectsWithoutKeys(IList allObjects, string keyProperty, params int[] excludedKeyValues)
        {
            ArrayList validObjects = new ArrayList();
            foreach (object obj in allObjects)
            {
                int currKey = (int)ReflectionUtil.GetPublicPropertyValue(obj, keyProperty);
                bool isExcludedKey = ArrayUtil.Contains(excludedKeyValues, currKey);
                if (!isExcludedKey)
                    validObjects.Add(obj);
            }

            return validObjects;
        }

        /// <summary>
        /// Returns zero-based index of an object with the specified key.
        /// </summary>
        /// <param name="objects">List of objects.</param>
        /// <param name="keyProperty">Name of the property that contains key values.</param>
        /// <param name="key">Key value of object that is to be found in the source list.</param>
        /// <returns>Index of the object; -1 if not found.</returns>
        public static int IndexOf(IList objects, string keyProperty, object key)
        {
            for (int index = 0; index < objects.Count; index++)
            {
                object currKey = ReflectionUtil.GetPublicPropertyValue(objects[index], keyProperty);
                if (currKey.Equals(key))
                    return index;
            }

            return -1;
        }

        /// <summary>
        /// Gets all objects with the specified keys.
        /// </summary>
        /// <param name="allObjects">Source list.</param>
        /// <param name="keyProperty">Name of the property that contains key values.</param>
        /// <param name="allowedKeyValues">Key values of object that will be added to output list.</param>
        /// <returns>A list of objects with the specified keys.</returns>
        public static ArrayList GetObjectsWithKeys(IList allObjects, string keyProperty, params int[] allowedKeyValues)
        {
            ArrayList validObjects = new ArrayList();
            int[] allKeys = ToIntArray(allObjects, keyProperty);
            for (int i = 0; i < allKeys.Length; i++)
            {
                if (Contains(allowedKeyValues, allKeys[i]))
                    validObjects.Add(allObjects[i]);
            }

            return validObjects;
        }

        /// <summary>
        /// Gets all object with the specified keys.
        /// </summary>
        /// <typeparam name="TList">Type of the list which is returned from the method.</typeparam>
        /// <typeparam name="TElement">Type of elements contained in the input and output lists.</typeparam>
        /// <typeparam name="TKey">Type of the values in the key property.</typeparam>
        /// <param name="allObjects">Source list.</param>
        /// <param name="keyPropertyName">Name of the property that contains key values.</param>
        /// <param name="allowedKeyValues">Key values of object that will be added to output list.</param>
        /// <returns>A list of objects with the specified keys.</returns>
        public static TList GetObjectsWithKeys<TList, TElement, TKey>(IEnumerable allObjects, string keyPropertyName, params TKey[] allowedKeyValues)
            where TList : IList, new()
        {
            TList validObjects = new TList();
            PropertyInfo keyProperty = typeof(TElement).GetProperty(keyPropertyName);
            foreach (TElement obj in allObjects)
            {
                TKey key = (TKey)keyProperty.GetValue(obj, null);
                bool isAllowed = (Array.IndexOf<TKey>(allowedKeyValues, key) >= 0);
                if (isAllowed)
                    validObjects.Add(obj);
            }

            return validObjects;
        }

        /// <summary>
        /// Gets a single object with the specified key.
        /// </summary>
        /// <param name="allObjects">Source list.</param>
        /// <param name="keyProperty">Name of the property that contains key values.</param>
        /// <param name="key">Key value of object that is to be found in the source list.</param>
        /// <returns>Object with the given key; null if not found.</returns>
        public static object GetObjectByKey(IList allObjects, string keyProperty, object key)
        {
            int objectIndex = IndexOf(allObjects, keyProperty, key);
            if (objectIndex >= 0)
                return allObjects[objectIndex];
            else
                return null;
        }

        /// <summary>
        /// Gets a singe object with the specified key.
        /// </summary>
        /// <typeparam name="TElement">Type of elements contained in the input and output lists.</typeparam>
        /// <typeparam name="TKey">Type of the values in the key property.</typeparam>
        /// <param name="allObjects">Source list.</param>
        /// <param name="keyPropertyName">Name of the property that contains key values.</param>
        /// <param name="key">Key value of object that is to be found in the source list.</param>
        /// <returns>Object with the given key; null if not found.</returns>
        public static TElement GetObjectByKey<TElement, TKey>(IEnumerable allObjects, string keyPropertyName, TKey key)
            where TElement : class
            where TKey : IEquatable<TKey>
        {
            PropertyInfo keyProperty = typeof(TElement).GetProperty(keyPropertyName);
            foreach (TElement obj in allObjects)
            {
                TKey currObjKey = (TKey)keyProperty.GetValue(obj, null);
                bool isMatch = currObjKey.Equals(key);
                if (isMatch)
                    return obj;
            }

            return null;
        }

        /// <summary>
        /// Gets all object that don't have the specified keys.
        /// </summary>
        /// <typeparam name="TList">Type of the list which is returned from the method.</typeparam>
        /// <typeparam name="TElement">Type of elements contained in the input and output lists.</typeparam>
        /// <typeparam name="TKey">Type of the values in the key property.</typeparam>
        /// <param name="allObjects">Source list.</param>
        /// <param name="keyPropertyName">Name of the property that contains key values.</param>
        /// <param name="excludedKeyValues">Key values of object that will <b>not</b> be added to output list.</param>
        /// <returns>A list of objects without the specified keys.</returns>
        public static TList GetObjectWithoutKeys<TList, TElement, TKey>(IEnumerable allObjects, string keyPropertyName, params TKey[] excludedKeyValues)
            where TList : IList, new()
        {
            TList validObjects = new TList();
            PropertyInfo keyProperty = typeof(TElement).GetProperty(keyPropertyName);
            foreach (TElement obj in allObjects)
            {
                TKey key = (TKey)keyProperty.GetValue(obj, null);
                bool isAllowed = (Array.IndexOf<TKey>(excludedKeyValues, key) < 0);
                if (isAllowed)
                    validObjects.Add(obj);
            }

            return validObjects;
        }

        /// <summary>
        /// Creates a distinct union of two lists. All object with duplicate key values are eliminated.
        /// </summary>
        /// <param name="lhs">Left-hand side list.</param>
        /// <param name="rhs">Right-hand side list.</param>
        /// <param name="uniqueField">Field with distinct values. Objects in both lists must contain this property/field.</param>
        /// <returns>Distinct union.</returns>
        public static ArrayList UnionDistinct(IList lhs, IList rhs, string uniqueField)
        {
            ArrayList distinctUnion = new ArrayList();
            foreach (object leftMember in lhs)
            {
                object keyValue = ReflectionUtil.GetPublicPropertyValue(leftMember, uniqueField);
                bool alreadyInDistinctList = (IndexOf(distinctUnion, uniqueField, keyValue) >= 0);
                if (!alreadyInDistinctList)
                    distinctUnion.Add(leftMember);
            }

            foreach (object rightMember in rhs)
            {
                object keyValue = ReflectionUtil.GetPublicPropertyValue(rightMember, uniqueField);
                bool alreadyInDistinctList = (IndexOf(distinctUnion, uniqueField, keyValue) >= 0);
                if (!alreadyInDistinctList)
                    distinctUnion.Add(rightMember);
            }

            return distinctUnion;
        }

        /// <summary>
        /// Returns an intersection of two lists.
        /// </summary>
        /// <param name="leftList">First list.</param>
        /// <param name="rightList">Second list.</param>
        /// <param name="keyProperty">Field used to compare objects. Objects in both lists must contain this property/field.</param>
        /// <returns>Intersection. Contains only objects that are found in both arrays.</returns>
        public static ArrayList Intersect(IList leftList, IList rightList, string keyProperty)
        {
            ArrayList intersection = new ArrayList();
            foreach (object leftMember in leftList)
            {
                object keyValue = ReflectionUtil.GetPublicPropertyValue(leftMember, keyProperty);
                bool isInBothLists = (IndexOf(rightList, keyProperty, keyValue) >= 0);
                if (isInBothLists)
                    intersection.Add(leftMember);
            }

            return intersection;
        }

        /// <summary>
        /// Creates a union of two arrays.
        /// </summary>
        /// <param name="lhs">Left-hand side array.</param>
        /// <param name="rhs">Right-hand side array.</param>
        /// <returns>Union of arrays.</returns>
        public static int[] Union(int[] lhs, int[] rhs)
        {
            int[] union = new int[lhs.Length + rhs.Length];

            int idx = 0;
            foreach (int number in lhs)
                union[idx++] = number;
            foreach (int number in rhs)
                union[idx++] = number;

            return union;
        }

        /// <summary>
        /// Creates a union of two lists.
        /// </summary>
        /// <param name="lhs">Left-hand side list.</param>
        /// <param name="rhs">Right-hand side list.</param>
        /// <returns>Union of lists.</returns>
        public static ArrayList Union(IList lhs, IList rhs)
        {
            ArrayList unionAll = new ArrayList();
            unionAll.AddRange(lhs);
            unionAll.AddRange(rhs);
            return unionAll;
        }

        /// <summary>
        /// Creates a union of provided collections.
        /// </summary>
        /// <typeparam name="TList">Type of the list which is returned from the method.</typeparam>
        /// <typeparam name="TElement">Type of elements contained in the input and output collections.</typeparam>
        /// <param name="collections">Source collections whose elements will be coppied to union list.</param>
        /// <returns>A list of all objects in the provided collections.</returns>
        public static TList Union<TList, TElement>(params IEnumerable[] collections)
            where TList : IList, new()
        {
            TList united = new TList();
            foreach (IEnumerable list in collections)
            {
                foreach (TElement element in list)
                    united.Add(element);
            }

            return united;
        }

        /// <summary>
        /// Creates a union of provided arrays.
        /// </summary>
        /// <typeparam name="T">Type of elements contained in the input and output collections.</typeparam>
        /// <param name="arrays">Source arrays whose elements will be coppied to union array.</param>
        /// <returns>An array of all objects in the provided arrays.</returns>
        public static T[] Union<T>(params Array[] arrays)
        {
            int totalCount = 0;
            foreach (Array arr in arrays)
                totalCount += arr.Length;

            T[] united = new T[totalCount];
            int idxInUnion = 0;
            foreach (Array arr in arrays)
            {
                foreach (T element in arr)
                {
                    united[idxInUnion] = element;
                    idxInUnion++;
                }
            }

            return united;
        }

        /// <summary>
        /// Creates a distinct union of two arrays. All duplicates are eliminated.
        /// </summary>
        /// <param name="lhs">Left-hand side array.</param>
        /// <param name="rhs">Right-hand side array.</param>
        /// <returns>Distinct union.</returns>
        public static int[] UnionDistinct(int[] lhs, int[] rhs)
        {
            int[] unionAll = Union(lhs, rhs);
            int[] distinctUnion = EliminateDuplicates(unionAll);
            return distinctUnion;
        }

        /// <summary>
        /// Creates a union of provided collections that contains only distinct values.
        /// </summary>
        /// <typeparam name="TList">Type of the list which is returned from the method.</typeparam>
        /// <typeparam name="TElement">Type of elements contained in the input and output collections.</typeparam>
        /// <param name="collections">Source collections whose elements will be coppied to union list.</param>
        /// <returns>A list of distinct values in the provided collections.</returns>
        public static TList UnionDistinct<TList, TElement>(params IEnumerable[] collections)
            where TList : IList, new()
        {
            TList unionAll = Union<TList, TElement>(collections);
            TList distinctUnion = EliminateDuplicates<TList, TElement>(unionAll);
            return distinctUnion;
        }

        /// <summary>
        /// Creates a union of provided collections that contains only objects with distinct keys.
        /// </summary>
        /// <typeparam name="TList">Type of the list which is returned from the method.</typeparam>
        /// <typeparam name="TElement">Type of elements contained in the input and output collections.</typeparam>
        /// <typeparam name="TKey">Type of the values in the key property.</typeparam>
        /// <param name="keyPropertyName">Name of the property that contains key values.</param>
        /// <param name="collections">Source collections whose elements will be coppied to union list.</param>
        /// <returns>A list of distinct objects in the provided collections.</returns>
        public static TList UnionDistinct<TList, TElement, TKey>(string keyPropertyName, params IEnumerable[] collections)
            where TList : IList, new()
        {
            TList unionAll = Union<TList, TElement>(collections);
            TList distinctUnion = EliminateDuplicates<TList, TElement, TKey>(unionAll, keyPropertyName);
            return distinctUnion;
        }

        /// <summary>
        /// Creates a union of provided collections that contains only objects with distinct keys.
        /// </summary>
        /// <typeparam name="TList">Type of the list which is returned from the method.</typeparam>
        /// <typeparam name="TElement">Type of elements contained in the input and output collections.</typeparam>
        /// <typeparam name="TKey">Type of the values in the key property.</typeparam>
        /// <param name="keyGetter">A delegate which gets the value of property that contains key values.</param>
        /// <param name="collections">Source collections whose elements will be coppied to union list.</param>
        /// <returns>A list of distinct objects in the provided collections.</returns>
        public static TList UnionDistinct<TList, TElement, TKey>(Delegates.Function<TKey, TElement> keyGetter, params IEnumerable[] collections)
            where TList : IList, new()
        {
            TList distinctUnion = new TList();
            Dictionary<TKey, object> usedKeys = new Dictionary<TKey, object>();
            foreach (IEnumerable col in collections)
            {
                foreach (TElement el in col)
                {
                    TKey key = keyGetter(el);
                    bool isAlreadyInList = usedKeys.ContainsKey(key);
                    if (!isAlreadyInList)
                    {
                        usedKeys.Add(key, null);
                        distinctUnion.Add(el);
                    }
                }
            }

            return distinctUnion;
        }

        /// <summary>
        /// Eliminates duplicates in the source array.
        /// </summary>
        /// <param name="arrayWithDuplicateValues">Array of integers that may contains duplicates.</param>
        /// <returns>Array of integers that contains only distinct values.</returns>
        public static int[] EliminateDuplicates(int[] arrayWithDuplicateValues)
        {
            ArrayList distinctValues = new ArrayList();
            foreach (int member in arrayWithDuplicateValues)
            {
                if (!Contains(distinctValues, member))
                    distinctValues.Add(member);
            }

            return ToIntArray(distinctValues);
        }

        /// <summary>
        /// Eliminates duplicate values in the source list.
        /// </summary>
        /// <typeparam name="TList">Type of the list which is returned from the method.</typeparam>
        /// <typeparam name="TElement">Type of elements contained in the input and output lists.</typeparam>
        /// <param name="listWithDuplicateValues">A list of values that may contain duplicates.</param>
        /// <returns>A list of distinct values.</returns>
        public static TList EliminateDuplicates<TList, TElement>(IEnumerable listWithDuplicateValues)
            where TList : IList, new()
        {
            TList distinctList = new TList();
            foreach (TElement element in listWithDuplicateValues)
            {
                bool alreadyInList = distinctList.Contains(element);
                if (!alreadyInList)
                    distinctList.Add(element);
            }

            return distinctList;
        }

        /// <summary>
        /// Eliminates objects with duplicate key values in the source list.
        /// </summary>
        /// <typeparam name="TList">Type of the list which is returned from the method.</typeparam>
        /// <typeparam name="TElement">Type of elements contained in the input and output lists.</typeparam>
        /// <typeparam name="TKey">Type of the values in the key property.</typeparam>
        /// <param name="listWithDuplicateValues">A list of objects that may contain duplicate key values.</param>
        /// <param name="keyPropertyName">Name of the property that contains key values.</param>
        /// <returns>A list of objects with distinct keys.</returns>
        public static TList EliminateDuplicates<TList, TElement, TKey>(IEnumerable listWithDuplicateValues, string keyPropertyName)
            where TList : IList, new()
        {
            TList distinctList = new TList();
            Dictionary<TKey, object> usedKeys = new Dictionary<TKey, object>();
            PropertyInfo keyProperty = typeof(TElement).GetProperty(keyPropertyName);
            foreach (TElement element in listWithDuplicateValues)
            {
                TKey currObjKey = (TKey)keyProperty.GetValue(element, null);
                bool alreadyInList = usedKeys.ContainsKey(currObjKey);
                if (!alreadyInList)
                {
                    distinctList.Add(element);
                    usedKeys.Add(currObjKey, null);
                }
            }

            return distinctList;
        }

        /// <summary>
        /// Eliminates duplicate objects in the source list.
        /// </summary>
        /// <typeparam name="TList">Type of the list which is returned from the method.</typeparam>
        /// <typeparam name="TElement">Type of elements contained in the input and output lists.</typeparam>
        /// <param name="listWithDuplicateValues">A list of objects that may contain duplicate key values.</param>
        /// <param name="comparison">The Comparison(TElement) delegate that defines how elements are compared.</param>
        /// <returns>A list of distinct objects.</returns>
        public static TList EliminateDuplicates<TList, TElement>(IEnumerable listWithDuplicateValues, Comparison<TElement> comparison)
            where TList : IList, new()
        {
            TList distinctList = new TList();
            foreach (TElement current in listWithDuplicateValues)
            {
                bool alreadyInCollection = Exists<TElement>(distinctList, (existing) => (0 == comparison(existing, current)));
                if (!alreadyInCollection)
                    distinctList.Add(current);
            }

            return distinctList;
        }

        /// <summary>
        /// Gets non-distinct objects from the source list.
        /// </summary>
        /// <typeparam name="TList">Type of the list which is returned from the method.</typeparam>
        /// <typeparam name="TElement">Type of elements contained in the input and output lists.</typeparam>
        /// <param name="listWithDuplicateValues">A list of objects that may contain duplicate key values.</param>
        /// <param name="comparison">The Comparison(TElement) delegate that defines how elements are compared.</param>
        /// <returns>A list of non-distinct objects.</returns>
        public static TList GetDuplicates<TList, TElement>(IEnumerable listWithDuplicateValues, Comparison<TElement> comparison)
            where TList : IList, new()
        {
            TList duplicates = new TList();
            foreach (TElement current in listWithDuplicateValues)
            {
                bool alreadyInCollection = Exists<TElement>(duplicates, (existing) => (0 == comparison(existing, current)));
                if (!alreadyInCollection)
                {
                    TList equalElements = FindAll<TList, TElement>(listWithDuplicateValues, (other) => (0 == comparison(other, current)));
                    if (equalElements.Count > 1)
                        duplicates.Add(current);
                }
            }

            return duplicates;
        }

        /// <summary>
        /// Removes specified values from source array.
        /// </summary>
        /// <param name="array">Source array.</param>
        /// <param name="valuesToBeExcludedFromArray">Values that are to be excluded from the source array.</param>
        /// <returns>Source array without the specified values.</returns>
        public static int[] GetDifference(int[] array, params int[] valuesToBeExcludedFromArray)
        {
            ArrayList difference = new ArrayList();
            foreach (int arrayMember in array)
            {
                if (!Contains(valuesToBeExcludedFromArray, arrayMember))
                    difference.Add(arrayMember);
            }

            return ToIntArray(difference);
        }

        /// <summary>
        /// Gets the set-theoretic difference of two provided values sets.
        /// </summary>
        /// <typeparam name="TList">Type of the list which is returned from the method.</typeparam>
        /// <typeparam name="TElement">Type of elements contained in the input and output lists.</typeparam>
        /// <param name="source">A set from which the elements/value are removed.</param>
        /// <param name="valuesToRemove">A set which contains the values to remove from the first set.</param>
        /// <returns>Source without the specified values.</returns>
        public static TList GetDifference<TList, TElement>(IEnumerable source, IEnumerable valuesToRemove)
            where TList : IList, new()
        {
            List<TElement> subtrahend = new List<TElement>();
            foreach (TElement elementToRemove in valuesToRemove)
                subtrahend.Add(elementToRemove);

            return GetDifference<TList, TElement>(source, subtrahend.ToArray());
        }

        /// <summary>
        /// Gets the set-theoretic difference of two provided values sets.
        /// </summary>
        /// <typeparam name="TList">Type of the list which is returned from the method.</typeparam>
        /// <typeparam name="TElement">Type of elements contained in the input and output lists.</typeparam>
        /// <param name="source">A set from which the elements/value are removed.</param>
        /// <param name="valuesToRemove">A set which contains the values to remove from the first set.</param>
        /// <returns>Source without the specified values.</returns>
        public static TList GetDifference<TList, TElement>(IEnumerable source, params TElement[] valuesToRemove)
            where TList : IList, new()
        {
            TList difference = new TList();
            foreach (TElement element in source)
            {
                bool survives = (Array.IndexOf<TElement>(valuesToRemove, element) < 0);
                if (survives)
                    difference.Add(element);
            }

            return difference;
        }

        /// <summary>
        /// Returns an intersection of two arrays.
        /// </summary>
        /// <param name="leftArray">First array.</param>
        /// <param name="rightArray">Second array.</param>
        /// <returns>Intersection. Contains only values that are found in both arrays.</returns>
        public static int[] Intersect(int[] leftArray, int[] rightArray)
        {
            ArrayList intersection = new ArrayList();
            foreach (int leftMember in leftArray)
            {
                if (Contains(rightArray, leftMember))
                    intersection.Add(leftMember);
            }

            return ToIntArray(intersection);
        }

        /// <summary>
        /// Gets the set-theoretic difference of two provided values sets.
        /// </summary>
        /// <typeparam name="TList">Type of the list which is returned from the method.</typeparam>
        /// <typeparam name="TElement">Type of elements contained in the input and output lists.</typeparam>
        /// <param name="leftList">First list.</param>
        /// <param name="rightList">Second list.</param>
        /// <returns>The set that contains all elements of 1st list that also belong to 2nd list.</returns>
        public static TList Intersect<TList, TElement>(IEnumerable leftList, IEnumerable rightList)
            where TList : IList, new()
            where TElement : IEquatable<TElement>
        {
            TList intersection = new TList();
            foreach (TElement leftMember in leftList)
            {
                bool isInBothLists = Contains<TElement>(rightList, leftMember);
                if (isInBothLists)
                    intersection.Add(leftMember);
            }

            return intersection;
        }

        /// <summary>
        /// Gets the set-theoretic difference of two provided values sets.
        /// </summary>
        /// <typeparam name="TList">Type of the list which is returned from the method.</typeparam>
        /// <typeparam name="TElement">Type of elements contained in the input and output lists.</typeparam>
        /// <typeparam name="TKey">Type of the values in the key property.</typeparam>
        /// <param name="leftList">First list.</param>
        /// <param name="rightList">Second list.</param>
        /// <param name="keyPropertyName">Name of the property that contains key values.</param>
        /// <returns>The set that contains all elements of 1st list that also belong to 2nd list.</returns>
        public static TList Intersect<TList, TElement, TKey>(IEnumerable leftList, IEnumerable rightList, string keyPropertyName)
            where TList : IList, new()
            where TKey : IEquatable<TKey>
        {
            TList intersection = new TList();
            PropertyInfo keyProperty = typeof(TElement).GetProperty(keyPropertyName);
            foreach (TElement leftMember in leftList)
            {
                TKey key = (TKey)keyProperty.GetValue(leftMember, null);
                bool isInBothLists = Contains<TKey>(rightList, keyPropertyName, key);
                if (isInBothLists)
                    intersection.Add(leftMember);
            }

            return intersection;
        }

        /// <summary>
        /// Checks whether an array contains a given value.
        /// </summary>
        /// <param name="array">Array.</param>
        /// <param name="val">Value to find in array.</param>
        /// <returns>True if array contains the given value; false otherwise.</returns>
        public static bool Contains(object[] array, object val)
        {
            foreach (object arrayMember in array)
            {
                if (arrayMember == val)
                    return true;
            }

            return false;
        }

        /// <summary>
        /// Checks whether an array contains a given value.
        /// </summary>
        /// <param name="array">Array.</param>
        /// <param name="val">Value to find in array.</param>
        /// <returns>True if array contains the given value; false otherwise.</returns>
        public static bool Contains(int[] array, int val)
        {
            foreach (int arrayMember in array)
            {
                if (arrayMember == val)
                    return true;
            }

            return false;
        }

        /// <summary>
        /// Checks whether a list contains a given integer value.
        /// </summary>
        /// <param name="integers">List of integers.</param>
        /// <param name="val">Value to find in array.</param>
        /// <returns>True if array contains the given value; false otherwise.</returns>
        private static bool Contains(IList integers, int val)
        {
            foreach (int arrayMember in integers)
            {
                if (arrayMember == val)
                    return true;
            }

            return false;
        }

        /// <summary>
        /// Checks whether a collection contains the specified value.
        /// </summary>
        /// <typeparam name="TElement">Type of elements in the collection.</typeparam>
        /// <param name="collection">A collection which will be scanned.</param>
        /// <param name="value">Value to find the collection.</param>
        /// <returns><b>true</b> if array contains the given value; <b>false</b> otherwise.</returns>
        public static bool Contains<TElement>(IEnumerable collection, TElement value)
            where TElement : IEquatable<TElement>
        {
            foreach (TElement element in collection)
            {
                bool isMatch = element.Equals(value);
                if (isMatch)
                    return true;
            }

            return false;
        }

        /// <summary>
        /// Checks whether a collection contains an object with the specified key value.
        /// </summary>
        /// <typeparam name="TKey">Type of the values in the key property.</typeparam>
        /// <param name="collection">A list or an array of objects.</param>
        /// <param name="keyPropertyName">Name of the property that contains key values.</param>
        /// <param name="key">Key value of object that is to be found in the source list.</param>
        /// <returns><b>true</b> if array contains the given value; <b>false</b> otherwise.</returns>
        public static bool Contains<TKey>(IEnumerable collection, string keyPropertyName, TKey key)
            where TKey : IEquatable<TKey>
        {
            int index = IndexOf<TKey>(collection, keyPropertyName, key);
            bool isFound = (index >= 0) ? true : false;
            return isFound;
        }

        #endregion Sets.

        #region Aggregate functions.

        /// <summary>
        /// Returns the smallest value in the array.
        /// </summary>
        /// <param name="numbers">An array of numbers to inspect.</param>
        /// <returns>The smallest number. Zero if collection iz empty.</returns>
        public static int Min(params int[] numbers)
        {
            return Min<int>(numbers);
        }

        /// <summary>
        /// Returns the smallest value in the array.
        /// </summary>
        /// <typeparam name="TElement">Type of elements in the collection.</typeparam>
        /// <param name="array">An array of values to inspect.</param>
        /// <returns>The smallest element. Default type value if collection iz empty.</returns>
        public static TElement Min<TElement>(params TElement[] array)
            where TElement : IComparable<TElement>
        {
            return Min<TElement>((IEnumerable)array);
        }

        /// <summary>
        /// Returns the smallest value in the collection.
        /// </summary>
        /// <typeparam name="TElement">Type of elements in the collection.</typeparam>
        /// <param name="collection">A collection of values to inspect.</param>
        /// <returns>The smallest element. Default type value if collection iz empty.</returns>
        public static TElement Min<TElement>(IEnumerable collection)
            where TElement : IComparable<TElement>
        {
            IEnumerator vector = collection.GetEnumerator();
            bool isEmpty = !vector.MoveNext();
            if (isEmpty)
                return default(TElement);

            TElement min = (TElement)vector.Current;
            foreach (TElement element in collection)
            {
                bool isLessThanMin = (element.CompareTo(min) < 0);
                if (isLessThanMin)
                    min = element;
            }

            return min;
        }

        /// <summary>
        /// Returns the object with the smallest comparation property value.
        /// </summary>
        /// <typeparam name="TElement">Type of elements in the collection. Must be a reference type, ie. class.</typeparam>
        /// <typeparam name="TComparableProperty">Type of the values in the property by which the objects are compared.</typeparam>
        /// <param name="collection">A collection of objects to inspect.</param>
        /// <param name="comparablePropertyName">Name of the property by which the object are compared.</param>
        /// <returns>Object with the smallest comparation value. <b>null</b> if collection is empty.</returns>
        public static TElement Min<TElement, TComparableProperty>(IEnumerable collection, string comparablePropertyName)
            where TElement : class
            where TComparableProperty : IComparable<TComparableProperty>
        {
            IEnumerator vector = collection.GetEnumerator();
            bool isEmpty = !vector.MoveNext();
            if (isEmpty)
                return default(TElement);

            PropertyInfo comparableProperty = typeof(TElement).GetProperty(comparablePropertyName);
            TElement objWithMinProperty = (TElement)vector.Current;
            TComparableProperty minProperty = (TComparableProperty)comparableProperty.GetValue(objWithMinProperty, null);
            foreach (TElement element in collection)
            {
                TComparableProperty compareBy = (TComparableProperty)comparableProperty.GetValue(element, null);
                bool isLessThanMin = (compareBy.CompareTo(minProperty) < 0);
                if (isLessThanMin)
                {
                    minProperty = compareBy;
                    objWithMinProperty = element;
                }
            }

            return objWithMinProperty;
        }

        /// <summary>
        /// Returns the object with the smallest comparisson value.
        /// </summary>
        /// <typeparam name="TElement">Type of elements in the collection. Must be a reference type, ie. class.</typeparam>
        /// <param name="collection">A collection of objects to inspect.</param>
        /// <param name="comparison">The Comparison(TElement) delegate that defines how elements are compared.</param>
        /// <returns>Object with the smallest comparation value. <b>null</b> if collection is empty.</returns>
        public static TElement Min<TElement>(IEnumerable collection, Comparison<TElement> comparison)
            where TElement : class
        {
            IEnumerator vector = collection.GetEnumerator();
            bool isEmpty = !vector.MoveNext();
            if (isEmpty)
                return default(TElement);

            TElement minElement = (TElement)vector.Current;
            foreach (TElement currElement in collection)
            {
                bool isLessThanMin = comparison(currElement, minElement) < 0;
                if (isLessThanMin)
                    minElement = currElement;
            }

            return minElement;
        }

        /// <summary>
        /// Returns the object with the smallest comparisson value.
        /// </summary>
        /// <typeparam name="TElement">Type of elements in the collection. Must be a reference type, ie. class.</typeparam>
        /// <typeparam name="TComparableProperty">Type of the values in the property by which the objects are compared.</typeparam>
        /// <param name="collection">A collection of objects to inspect.</param>
        /// <param name="compareByGetter">A delegate which gets the value of property by which the objects are compared.</param>
        /// <returns>Object with the smallest comparation value. <b>null</b> if collection is empty.</returns>
        public static TElement Min<TElement, TComparableProperty>(IEnumerable collection, Delegates.Function<TComparableProperty, TElement> compareByGetter)
            where TElement : class
            where TComparableProperty : IComparable<TComparableProperty>
        {
            IEnumerator vector = collection.GetEnumerator();
            bool isEmpty = !vector.MoveNext();
            if (isEmpty)
                return default(TElement);

            TElement minElement = (TElement)vector.Current;
            foreach (TElement currElement in collection)
            {
                TComparableProperty maxValue = compareByGetter(minElement);
                TComparableProperty currValue = compareByGetter(currElement);
                bool isLessThanMax = currValue.CompareTo(maxValue) < 0;
                if (isLessThanMax)
                    minElement = currElement;
            }

            return minElement;
        }

        /// <summary>
        /// Returns the smallest value in the collection or null.
        /// </summary>
        /// <typeparam name="TValue">Type of elements in the collection.</typeparam>
        /// <param name="collection">A collection of values to inspect.</param>
        /// <returns>The smallest value. <b>null</b> if collection is empty.</returns>
        public static TValue? MinValue<TValue>(IEnumerable collection)
            where TValue : struct, IComparable<TValue>
        {
            IEnumerator vector = collection.GetEnumerator();
            bool isEmpty = !vector.MoveNext();
            if (isEmpty)
                return null;

            TValue min = (TValue)vector.Current;
            foreach (TValue element in collection)
            {
                bool isLessThanMin = (element.CompareTo(min) < 0);
                if (isLessThanMin)
                    min = element;
            }

            return min;
        }

        /// <summary>
        /// Returns the smallest value in the collection or null.
        /// </summary>
        /// <typeparam name="TElement">Type of elements in the collection. Must be a reference type, ie. class.</typeparam>
        /// <typeparam name="TValue">Type of the values in the property which is compared.</typeparam>
        /// <param name="collection">A collection of objects whose properties are inspected.</param>
        /// <param name="valueGetter">A delegate which gets the value of property which is compared.</param>
        /// <returns>The smallest value. <b>null</b> if collection is empty.</returns>
        public static TValue? MinValue<TElement, TValue>(IEnumerable collection, Delegates.Function<TValue, TElement> valueGetter)
            where TElement : class
            where TValue : struct, IComparable<TValue>
        {
            TElement minElement = Min<TElement, TValue>(collection, valueGetter);
            if (minElement != null)
                return valueGetter(minElement);
            else
                return null;
        }

        /// <summary>
        /// Returns the greatest value in the array.
        /// </summary>
        /// <param name="numbers">Array of numbers to inspect. Zero if collection is empty.</param>
        /// <returns>The greatest number.</returns>
        public static int Max(params int[] numbers)
        {
            return Max<int>(numbers);
        }

        /// <summary>
        /// Returns the greatest value in the array.
        /// </summary>
        /// <typeparam name="TElement">Type of elements in the collection.</typeparam>
        /// <param name="array">An array of values to inspect.</param>
        /// <returns>The greatest element. Default type value if collection is empty.</returns>
        public static TElement Max<TElement>(params TElement[] array)
            where TElement : IComparable<TElement>
        {
            return Max<TElement>((IEnumerable)array);
        }

        /// <summary>
        /// Returns the greatest value in the collection.
        /// </summary>
        /// <typeparam name="TElement">Type of elements in the collection.</typeparam>
        /// <param name="collection">A collection of values to inspect.</param>
        /// <returns>The greatest element. Default type value if collection is empty.</returns>
        public static TElement Max<TElement>(IEnumerable collection)
            where TElement : IComparable<TElement>
        {
            IEnumerator vector = collection.GetEnumerator();
            bool isEmpty = !vector.MoveNext();
            if (isEmpty)
                return default(TElement);

            TElement max = (TElement)vector.Current;
            foreach (TElement element in collection)
            {
                bool isGreaterThanMax = (element.CompareTo(max) > 0);
                if (isGreaterThanMax)
                    max = element;
            }

            return max;
        }

        /// <summary>
        /// Returns the object with the greatest comparation property value.
        /// </summary>
        /// <typeparam name="TElement">Type of elements in the collection. Must be a reference type, ie. class.</typeparam>
        /// <typeparam name="TComparableProperty">Type of the values in the property by which the object are compared.</typeparam>
        /// <param name="collection">A collection of objects to inspect.</param>
        /// <param name="comparablePropertyName">Name of the property by which the object are compared.</param>
        /// <returns>Object with the greatest comparation value. <b>null</b> if collection is empty.</returns>
        public static TElement Max<TElement, TComparableProperty>(IEnumerable collection, string comparablePropertyName)
            where TElement : class
            where TComparableProperty : IComparable<TComparableProperty>
        {
            IEnumerator vector = collection.GetEnumerator();
            bool isEmpty = !vector.MoveNext();
            if (isEmpty)
                return default(TElement);

            PropertyInfo comparableProperty = typeof(TElement).GetProperty(comparablePropertyName);
            TElement objWithMaxProperty = (TElement)vector.Current;
            TComparableProperty maxProperty = (TComparableProperty)comparableProperty.GetValue(objWithMaxProperty, null);
            foreach (TElement element in collection)
            {
                TComparableProperty compareBy = (TComparableProperty)comparableProperty.GetValue(element, null);
                bool isGreaterThanMax = (compareBy.CompareTo(maxProperty) > 0);
                if (isGreaterThanMax)
                {
                    maxProperty = compareBy;
                    objWithMaxProperty = element;
                }
            }

            return objWithMaxProperty;
        }

        /// <summary>
        /// Returns the object with the greatest comparisson value.
        /// </summary>
        /// <typeparam name="TElement">Type of elements in the collection. Must be a reference type, ie. class.</typeparam>
        /// <param name="collection">A collection of objects to inspect.</param>
        /// <param name="comparison">The Comparison(TElement) delegate that defines how elements are compared.</param>
        /// <returns>Object with the greatest comparation value. <b>null</b> if collection is empty.</returns>
        public static TElement Max<TElement>(IEnumerable collection, Comparison<TElement> comparison)
            where TElement : class
        {
            IEnumerator vector = collection.GetEnumerator();
            bool isEmpty = !vector.MoveNext();
            if (isEmpty)
                return default(TElement);

            TElement maxElement = (TElement)vector.Current;
            foreach (TElement currElement in collection)
            {
                bool isGreaterThanMax = comparison(currElement, maxElement) > 0;
                if (isGreaterThanMax)
                    maxElement = currElement;
            }

            return maxElement;
        }

        /// <summary>
        /// Returns the object with the greatest comparisson value.
        /// </summary>
        /// <typeparam name="TElement">Type of elements in the collection. Must be a reference type, ie. class.</typeparam>
        /// <typeparam name="TComparableProperty">Type of the values in the property by which the objects are compared.</typeparam>
        /// <param name="collection">A collection of objects to inspect.</param>
        /// <param name="compareByGetter">A delegate which gets the value tha value of property by which the objects are compared.</param>
        /// <returns>Object with the greatest comparation value. <b>null</b> if collection is empty.</returns>
        public static TElement Max<TElement, TComparableProperty>(IEnumerable collection, Delegates.Function<TComparableProperty, TElement> compareByGetter)
            where TElement : class
            where TComparableProperty : IComparable<TComparableProperty>
        {
            IEnumerator vector = collection.GetEnumerator();
            bool isEmpty = !vector.MoveNext();
            if (isEmpty)
                return default(TElement);

            TElement maxElement = (TElement)vector.Current;
            foreach (TElement currElement in collection)
            {
                TComparableProperty maxValue = compareByGetter(maxElement);
                TComparableProperty currValue = compareByGetter(currElement);
                bool isGreaterThanMax = currValue.CompareTo(maxValue) > 0;
                if (isGreaterThanMax)
                    maxElement = currElement;
            }

            return maxElement;
        }

        /// <summary>
        /// Returns the greatest value in the collection or null.
        /// </summary>
        /// <typeparam name="TValue">Type of elements in the collection.</typeparam>
        /// <param name="collection">A collection of values to inspect.</param>
        /// <returns>The greatest value. <b>null</b> if collection is empty.</returns>
        public static TValue? MaxValue<TValue>(IEnumerable collection)
            where TValue : struct, IComparable<TValue>
        {
            IEnumerator vector = collection.GetEnumerator();
            bool isEmpty = !vector.MoveNext();
            if (isEmpty)
                return null;

            TValue max = (TValue)vector.Current;
            foreach (TValue element in collection)
            {
                bool isGreaterThanMax = (element.CompareTo(max) > 0);
                if (isGreaterThanMax)
                    max = element;
            }

            return max;
        }

        /// <summary>
        /// Returns the greatest value in the collection or null.
        /// </summary>
        /// <typeparam name="TElement">Type of elements in the collection. Must be a reference type, ie. class.</typeparam>
        /// <typeparam name="TValue">Type of the values in the property which is compared.</typeparam>
        /// <param name="collection">A collection of objects whose properties are inspected.</param>
        /// <param name="valueGetter">A delegate which gets the value of property which is compared.</param>
        /// <returns>The greatest value. <b>null</b> if collection is empty.</returns>
        public static TValue? MaxValue<TElement, TValue>(IEnumerable collection, Delegates.Function<TValue, TElement> valueGetter)
            where TElement : class
            where TValue : struct, IComparable<TValue>
        {
            TElement maxElement = Max<TElement, TValue>(collection, valueGetter);
            if (maxElement != null)
                return valueGetter(maxElement);
            else
                return null;
        }

        /// <summary>
        /// Returns the number of elements that match the conditions defined by the specified predicate.
        /// </summary>
        /// <typeparam name="TElement">Type of elements contained in the collection.</typeparam>
        /// <param name="collection">A collection.</param>
        /// <param name="match">The Predicate(TElement) delegate that defines the conditions of the elements to search for.</param>
        /// <returns>Number of elements that match the conditions defined by the specified predicate.</returns>
        public static int Count<TElement>(IEnumerable collection, Predicate<TElement> match)
        {
            int count = 0;
            foreach (TElement obj in collection)
            {
                if (match(obj))
                    count++;
            }

            return count;
        }

        #endregion Aggregate functions.

        #region Sorting.

        /// <summary>
        /// Sorts a list using default comparer.
        /// </summary>
        /// <param name="objectsToSort">A list of objects to sort.</param>
        /// <returns>Sorted objects.</returns>
        public static ArrayList Sort(IEnumerable objectsToSort)
        {
            ArrayList list = ToArrayList(objectsToSort);
            list.Sort();
            return list;
        }

        private class PropertyComparer : IComparer
        {
            static readonly Comparer valueComparer = new Comparer(CultureInfo.InvariantCulture);
            string property;

            public PropertyComparer(string property)
            {
                this.property = property;
            }

            public int Compare(object x, object y)
            {
                object xProperty = ReflectionUtil.GetPublicPropertyValue(x, this.property);
                object yProperty = ReflectionUtil.GetPublicPropertyValue(y, this.property);

                return valueComparer.Compare(xProperty, yProperty);
            }
        }

        /// <summary>
        /// Sorts a list.
        /// </summary>
        /// <param name="objectsToSort">A list of objects to sort.</param>
        /// <param name="orderByProperty">Object property whose values are to be sorted.</param>
        /// <returns>Sorted objects.</returns>
        public static ArrayList Sort(IEnumerable objectsToSort, string orderByProperty)
        {
            ArrayList sortedList = ToArrayList(objectsToSort);
            sortedList.Sort(new PropertyComparer(orderByProperty));
            return sortedList;
        }

        /// <summary>
        /// Sorts a list.
        /// </summary>
        /// <param name="objectsToSort">A list of objects to sort.</param>
        /// <param name="orderByProperty">Object property whose values are to be sorted.</param>
        /// <param name="ascending">Specifies whether the values in the specified property should be sorted in ascending order, from lowest value to highest value.</param>
        /// <returns>Sorted objects.</returns>
        public static ArrayList Sort(IEnumerable objectsToSort, string orderByProperty, bool ascending)
        {
            ArrayList sortedObjects = Sort(objectsToSort, orderByProperty);
            if (!ascending)
                sortedObjects.Reverse();

            return sortedObjects;
        }

        /// <summary>
        /// Sorts a collection using default comparer.
        /// </summary>
        /// <typeparam name="TList">Type of the list which is returned from the method.</typeparam>
        /// <typeparam name="TElement">Type of elements contained in the collection.</typeparam>
        /// <param name="collection">A collection of objects to sort.</param>
        /// <returns>Sorted list.</returns>
        public static TList Sort<TList, TElement>(IEnumerable collection)
            where TList : IList, new()
            where TElement : IComparable
        {
            TList sortedList = new TList();
            MethodInfo sortMethod = typeof(TList).GetMethod("Sort", new Type[0]);
            if (sortMethod != null)
            {
                Copy(collection, sortedList);
                sortMethod.Invoke(sortedList, null);
            }
            else
            {
                List<TElement> intermediateSortedList = new List<TElement>();
                Copy(collection, intermediateSortedList);
                intermediateSortedList.Sort();
                Copy(intermediateSortedList, sortedList);
            }

            return sortedList;
        }

        private static void Copy(IEnumerable source, IList target)
        {
            foreach (object obj in source)
                target.Add(obj);
        }

        /// <summary>
        /// Sorts a collection using the specified comparison.
        /// </summary>
        /// <typeparam name="TList">Type of the list which is returned from the method.</typeparam>
        /// <typeparam name="TElement">Type of elements contained in the collection.</typeparam>
        /// <param name="collection">A collection of objects to sort.</param>
        /// <param name="comparison">The Comparison(TElement) delegate that defines how elements are compared.</param>
        /// <returns>Sorted list.</returns>
        public static TList Sort<TList, TElement>(IEnumerable collection, Comparison<TElement> comparison)
            where TList : IList, new()
        {
            TList sortedList = new TList();
            MethodInfo sortMethod = typeof(TList).GetMethod("Sort", new Type[] { typeof(Comparison<TElement>) });
            if (sortMethod != null)
            {
                Copy(collection, sortedList);
                sortMethod.Invoke(sortedList, new object[] { comparison });
            }
            else
            {
                List<TElement> intermediateSortedList = new List<TElement>();
                Copy(collection, intermediateSortedList);
                intermediateSortedList.Sort(comparison);
                Copy(intermediateSortedList, sortedList);
            }

            return sortedList;
        }

        /// <summary>
        /// Sorts a collection.
        /// </summary>
        /// <typeparam name="TList">Type of the list which is returned from the method.</typeparam>
        /// <typeparam name="TElement">Type of elements contained in the collection.</typeparam>
        /// <typeparam name="TComparableProperty">Type of the values in the property by which the objects are ordered.</typeparam>
        /// <param name="collection">A collection of objects to sort.</param>
        /// <param name="orderByGetter">A delegate which gets the value tha value of property by which the objects are ordered.</param>
        /// <returns>Sorted list.</returns>
        public static TList Sort<TList, TElement, TComparableProperty>(IEnumerable collection, Delegates.Function<TComparableProperty, TElement> orderByGetter)
            where TList : IList, new()
            where TComparableProperty : IComparable<TComparableProperty>
        {
            return Sort<TList, TElement, TComparableProperty>(collection, /*asc*/ true, orderByGetter);
        }

        /// <summary>
        /// Sorts a collection.
        /// </summary>
        /// <typeparam name="TList">Type of the list which is returned from the method.</typeparam>
        /// <typeparam name="TElement">Type of elements contained in the collection.</typeparam>
        /// <typeparam name="TComparableProperty">Type of the values in the property by which the objects are ordered.</typeparam>
        /// <param name="collection">A collection of objects to sort.</param>
        /// <param name="ascending">Specifies whether the values in the specified property should be sorted in ascending order, from lowest value to highest value.</param>
        /// <param name="orderByGetter">A delegate which gets the value tha value of property by which the objects are ordered.</param>
        /// <returns>Sorted list.</returns>
        public static TList Sort<TList, TElement, TComparableProperty>(IEnumerable collection, bool ascending, Delegates.Function<TComparableProperty, TElement> orderByGetter)
            where TList : IList, new()
            where TComparableProperty : IComparable<TComparableProperty>
        {
            Comparison<TElement> comparison;
            if (ascending)
                comparison = (x, y) => orderByGetter(x).CompareTo(orderByGetter(y));
            else
                comparison = (x, y) => orderByGetter(y).CompareTo(orderByGetter(x));

            return Sort<TList, TElement>(collection, comparison);
        }

        #endregion Sorting.

        #region Concat.

        /// <summary>
        /// Concatenates the string representations of the elements in the specified list.
        /// </summary>
        /// <param name="list">A list of objects.</param>
        /// <param name="delimiter">Optional string which is used to delimit objects. Nullable.</param>
        /// <returns>The concatenated and delimited string representations of the values of the elements in the list.</returns>
        public static string Concat(IEnumerable list, string delimiter)
        {
            if (delimiter == null)
                delimiter = "";

            StringBuilder str = new StringBuilder();
            foreach (object element in list)
            {
                str.Append(element);
                str.Append(delimiter);
            }

            if (str.Length >= delimiter.Length)
                str.Remove(str.Length - delimiter.Length, delimiter.Length);

            return str.ToString();
        }

        /// <summary>
        /// Concatenates the string representations of the elements in the specified list.
        /// </summary>
        /// <param name="list">A list of objects.</param>
        /// <param name="delimiter">Optional string which is used to delimit objects. Nullable.</param>
        /// <param name="formatter">Formats elements of the list.</param>
        /// <returns>The concatenated and delimited string representations of the values of the elements in the list.</returns>
        public static string Concat(IEnumerable list, string delimiter, IMessageFormatter formatter)
        {
            if (delimiter == null)
                delimiter = "";

            StringBuilder str = new StringBuilder();
            foreach (object element in list)
            {
                str.Append(formatter.Format(element));
                str.Append(delimiter);
            }

            if (str.Length >= delimiter.Length)
                str.Remove(str.Length - delimiter.Length, delimiter.Length);

            return str.ToString();
        }

        /// <summary>
        /// Concatenates the string representations of the elements in the specified list.
        /// </summary>
        /// <typeparam name="TElement">Type of elements contained in the collection.</typeparam>
        /// <param name="collection">A collection of objects that contain the values to concatenate.</param>
        /// <param name="delimiter">Optional string which is used to delimit objects. Nullable.</param>
        /// <param name="getValueToConcat">A delegate to a method which returns value to concatenate.</param>
        /// <returns>The concatenated and delimited string representations of the values of the elements in the list.</returns>
        public static string Concat<TElement>(IEnumerable collection, string delimiter, Delegates.Function<object, TElement> getValueToConcat)
        {
            if (delimiter == null)
                delimiter = "";

            StringBuilder str = new StringBuilder();
            foreach (TElement element in collection)
            {
                object valToConcat = getValueToConcat(element);
                str.Append(valToConcat);
                str.Append(delimiter);
            }

            if (str.Length >= delimiter.Length)
                str.Remove(str.Length - delimiter.Length, delimiter.Length);

            return str.ToString();
        }

        /// <summary>
        /// Concatenates the string representations of the elements in the specified list.
        /// </summary>
        /// <typeparam name="TElement">Type of elements contained in the collection.</typeparam>
        /// <param name="collection">A collection of objects that contain the values to concatenate.</param>
        /// <param name="delimiter">Optional string which is used to delimit objects. Nullable.</param>
        /// <param name="formatter">Formats elements of the list.</param>
        /// <param name="getValueToConcat">A delegate to a method which returns value to concatenate.</param>
        /// <returns>The concatenated and delimited string representations of the values of the elements in the list.</returns>
        public static string Concat<TElement>(IEnumerable collection, string delimiter, IMessageFormatter formatter, Delegates.Function<object, TElement> getValueToConcat)
        {
            if (delimiter == null)
                delimiter = "";

            StringBuilder str = new StringBuilder();
            foreach (TElement element in collection)
            {
                object valToConcat = getValueToConcat(element);
                str.Append(formatter.Format(valToConcat));
                str.Append(delimiter);
            }

            if (str.Length >= delimiter.Length)
                str.Remove(str.Length - delimiter.Length, delimiter.Length);

            return str.ToString();
        }

        /// <summary>
        /// Splits a <see cref="List{T}"/> into multiple chunks.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="list">The list to be chunked.</param>
        /// <param name="chunkSize">The size of each chunk.</param>
        /// <returns>A list of chunks.</returns>
        public static List<List<T>> SplitIntoChunks<T>(List<T> list, int chunkSize)
        {
            if (chunkSize <= 0)
            {
                throw new ArgumentException("chunkSize must be greater than 0.");
            }

            List<List<T>> retVal = new List<List<T>>();
            int index = 0;
            while (index < list.Count)
            {
                int count = list.Count - index > chunkSize ? chunkSize : list.Count - index;
                retVal.Add(list.GetRange(index, count));

                index += chunkSize;
            }

            return retVal;
        }

        #endregion Concat.

        #region ForEach.

        /// <summary>
        /// Performs the specified action on each element of the collection.
        /// </summary>
        /// <typeparam name="TElement">Type of elements contained in the collection.</typeparam>
        /// <param name="collection">A collection.</param>
        /// <param name="action">The Action(TElement) delegate to perform on each element of the collection.</param>
        public static void ForEach<TElement>(IEnumerable collection, Action<TElement> action)
        {
            foreach (TElement el in collection)
                action(el);
        }

        #endregion ForEach.

        #region NextNegativeId.

        /// <summary>
        /// Computes a temporary negative ID which uniquely identifies a new record in the given collection.
        /// </summary>
        /// <typeparam name="TElement">Type of objects in the collection. Typically these are entities, business objects or ADO.NET data rows.</typeparam>
        /// <param name="collection">A collection which is to be inspected.</param>
        /// <param name="getElementId">A method which returns object's ID.</param>
        /// <returns>A negative integer.</returns>
        public static int NextNegativeId<TElement>(IEnumerable collection, Delegates.Function<int, TElement> getElementId)
        {
            int smallestId = 0;
            foreach (TElement el in collection)
            {
                int elementId = getElementId(el);
                if (elementId < smallestId)
                    smallestId = elementId;
            }

            int nextId = smallestId - 1;
            return nextId;
        }

        #endregion NextNegativeId.

        #region Dictionary conversion.

        /// <summary>
        /// Converts dictionary to its <see cref="DictionaryBindingList"/> representation.
        /// </summary>
        /// <typeparam name="TKey">Key type.</typeparam>
        /// <typeparam name="TValue">Value type.</typeparam>
        /// <param name="data">Dictionary to be changed.</param>
        /// <returns>Returns <see cref="DictionaryBindingList"/> representation of <paramref name="data"/>.</returns>
        public static DictionaryBindingList<TKey, TValue> ToBindingList<TKey, TValue>(this IDictionary<TKey, TValue> data)
        {
            return new DictionaryBindingList<TKey, TValue>(data);
        }

        #endregion Dictionary conversion.
    }

    /// <summary>
    /// Provides common operations which use advanced reflection features.
    /// </summary>
    public static class ReflectionUtil
    {
        #region InvokeMethod.

        /// <summary>
        /// Invokes a method.
        /// </summary>
        /// <param name="obj">Object whose definition (class) contains the specified method.</param>
        /// <param name="methodName">Method to be executed.</param>
        /// <param name="methodParameters">Method parameters.</param>
        /// <returns>Method's return value.</returns>
        public static object InvokeMethod(object obj, string methodName, object[] methodParameters)
        {
            Type[] parameterTypes = new Type[methodParameters.Length];
            bool cannotDetermineParameterTypes = false;
            for (int paramIdx = 0; paramIdx < methodParameters.Length; paramIdx++)
            {
                if (methodParameters[paramIdx] != null)
                    parameterTypes[paramIdx] = methodParameters[paramIdx].GetType();
                else
                    cannotDetermineParameterTypes = true;
            }

            MethodInfo method;
            if (cannotDetermineParameterTypes)
            {
                method = obj.GetType().GetMethod(methodName,
                    BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
            }
            else
            {
                method = obj.GetType().GetMethod(methodName,
                    BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance,
                    null, parameterTypes, null);
            }

            if (method == null)
                throw new Exception("Method " + methodName + " not found.");

            object retval = method.Invoke(obj, methodParameters);
            return retval;
        }

        #endregion InvokeMethod.

        #region InvokeStaticMethod.

        /// <summary>
        /// Invokes a static method.
        /// </summary>
        /// <param name="type">Type which contains the specified static method.</param>
        /// <param name="methodName">Method to be executed.</param>
        /// <param name="methodParameters">Method parameters.</param>
        /// <returns>Method's return value.</returns>
        public static object InvokeStaticMethod(Type type, string methodName, object[] methodParameters)
        {
            Type[] parameterTypes = new Type[methodParameters.Length];
            bool cannotDetermineParameterTypes = false;
            for (int paramIdx = 0; paramIdx < methodParameters.Length; paramIdx++)
            {
                if (methodParameters[paramIdx] != null)
                    parameterTypes[paramIdx] = methodParameters[paramIdx].GetType();
                else
                    cannotDetermineParameterTypes = true;
            }

            MethodInfo method;
            if (cannotDetermineParameterTypes)
            {
                method = type.GetMethod(methodName,
                    BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static);
            }
            else
            {
                method = type.GetMethod(methodName,
                    BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static,
                    null, parameterTypes, null);
            }

            if (method == null)
                throw new InvalidOperationException("Method " + methodName + " not found.");

            object retval = method.Invoke(null, methodParameters);
            return retval;
        }

        #endregion InvokeStaticMethod.

        #region CopyObject.

        /// <summary>
        /// Copies entire object graph to another instance of the same type.
        /// </summary>
        /// <param name="source">Source object.</param>
        /// <param name="destination">Destination object which is to receive the data contained in the source object.</param>
        public static void CopyObject(object source, object destination)
        {
            if (source.GetType() != destination.GetType())
                throw new InvalidOperationException("Source and destination objects are not of the same type. Source object type: " + source.GetType().ToString() + ". Destination object type: " + destination.GetType().ToString());

            // Climb the object hierarchy and copy all private, protected and public instance fields.
            Type type = source.GetType();
            while (type != null)
            {
                FieldInfo[] fieldsDeclaredInCurrentType = type.GetFields(BindingFlags.Instance | BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic);
                foreach (FieldInfo field in fieldsDeclaredInCurrentType)
                {
                    object currentFieldValue = field.GetValue(source);
                    field.SetValue(destination, currentFieldValue);
                }

                type = type.BaseType;
            }
        }

        #endregion CopyObject.

        #region CopyPublicProperties.

        /// <summary>
        /// Copies all values of public properties to another instance of the same type.
        /// </summary>
        /// <param name="source">Source object.</param>
        /// <param name="destination">Destination object which is to receive the data contained in the source object.</param>
        /// <remarks>Only properties which have getter and setter are copied.</remarks>
        public static void CopyPublicProperties(object source, object destination)
        {
            if (source.GetType() != destination.GetType())
                throw new Exception("Source and destination objects are not of the same type. Source object type: " + source.GetType().ToString() + ". Destination object type: " + destination.GetType().ToString());

            PropertyInfo[] allProperties = source.GetType().GetProperties();
            foreach (PropertyInfo prop in allProperties)
            {
                bool hasGetterAndSetter = (prop.CanWrite && prop.CanRead);
                if (!hasGetterAndSetter)
                    continue;

                object val = prop.GetValue(source, null);
                prop.SetValue(destination, val, null);
            }
        }

        #endregion CopyPublicProperties.

        #region GetPublicPropertyValue.

        /// <summary>
        /// Searches for the public property with the specified name and returns its value.
        /// </summary>
        /// <param name="obj">The object whose property value will be returned.</param>
        /// <param name="propertyName">Name of the public property to get.</param>
        /// <returns>The property value.</returns>
        public static object GetPublicPropertyValue(object obj, string propertyName)
        {
            PropertyInfo prop = obj.GetType().GetProperty(propertyName);
            return prop.GetValue(obj, null);
        }

        #endregion GetPublicPropertyValue.

        #region FindMember.

        const BindingFlags allInstanceMembers = BindingFlags.Instance | BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic;

        /// <summary>
        /// Tries to find a member in object's class hierarchy.
        /// </summary>
        /// <param name="obj">Object whose type hierarchy is inspected.</param>
        /// <param name="memberName">Name of the field or property to find.</param>
        /// <param name="field">A <see cref="FieldInfo"/> instance if matching field is found; <b>null</b> otherwise.</param>
        /// <param name="property">A <see cref="PropertyInfo"/> instance if matching property is found; <b>null</b> otherwise.</param>
        /// <returns><b>true</b> if member with the specified name was found; <b>false</b> otherwise.</returns>
        public static bool FindMember(object obj, string memberName, out FieldInfo field, out PropertyInfo property)
        {
            field = null;
            property = null;
            Type objType = null;
            bool foundMember = false;
            while (!foundMember)
            {
                objType = (objType == null) ? obj.GetType() : objType.BaseType;
                if (objType == null)
                    break;

                field = objType.GetField(memberName, allInstanceMembers);
                if (field == null)
                    property = objType.GetProperty(memberName, allInstanceMembers);

                foundMember = (field != null || property != null);
            }

            return foundMember;
        }

        #endregion FindMember.

        #region TrySetValueAtPath.

        static readonly IMessageFormatter DefaultFormatter = new MessageFormatter();

        /// <summary>
        /// Tries to set the value at the specified path in the object graph.
        /// </summary>
        /// <param name="component">Component/object whose object graph is analyzed and whose sub-component is to receive the value.</param>
        /// <param name="path">Array of public property names and indexer arguments.</param>
        /// <param name="value">Value to set in the final sub-component of the path.</param>
        /// <param name="logErrorsAsWarnings">Whether to log all encountered errors are logged as warnings (see <see cref="Log.AppWarning"/>).</param>
        /// <returns><b>true</b> if the operation was successfull; <b>false</b> otherwise.</returns>
        public static bool TrySetValueAtPath(object component, string[] path, object value, bool logErrorsAsWarnings)
        {
            // Imaginary example:
            // this.btn.Style["display"].Value = "none";
            // Style/display/Value
            // Get Style component
            // Get display component
            // Write to Value property

            object subComponent = component;
            int idxSegment = 0;
            while (idxSegment < path.Length)
            {
                string[] unprocessedPath = new string[path.Length - idxSegment];
                Array.Copy(path, idxSegment, unprocessedPath, 0, unprocessedPath.Length);

                bool subComponentReceivesTheValue;
                if (idxSegment == path.Length - 1)
                {
                    // End of path. We expect that the component represents a property or a single argument indexer.
                    subComponentReceivesTheValue = true;
                }
                else
                {
                    // Check if we have reached an indexer whose parameters can be parsed from the path tail.
                    PropertyInfo indexer = FindMatchingIndexer(subComponent, unprocessedPath);
                    subComponentReceivesTheValue = (indexer != null);
                }

                if (subComponentReceivesTheValue)
                {
                    // Write and exit.
                    bool isSuccess = WriteToPropertyOrIndexer(subComponent, unprocessedPath, value, logErrorsAsWarnings);
                    return isSuccess;
                }
                else
                {
                    int usedPathSegmentCount;
                    subComponent = GetSubComponent(subComponent, unprocessedPath, out usedPathSegmentCount, logErrorsAsWarnings);
                    idxSegment += usedPathSegmentCount;
                }

                bool pathDoesntMatchObjectGraph = (subComponent == null);
                if (pathDoesntMatchObjectGraph)
                {
                    if (logErrorsAsWarnings)
                    {
                        //Dictionary<string, object> errDetails = new Dictionary<string, object>();
                        //errDetails.Add("Component type", component.GetType());
                        //errDetails.Add("Path", GetPathString(path));
                        //errDetails.Add("Value", value);
                        //Log.AppWarning("ReflectionUtil.SetValueAtPath", "Path doesn't match component's object graph.", errDetails);
                    }

                    return false;
                }
            }

            return false;
        }

        #region FindMatchingIndexer.

        static Dictionary<Type, object> typesWithMultipleIndexers = new Dictionary<Type, object>();

        private static PropertyInfo FindMatchingIndexer(object obj, string[] txtIndexerArgs)
        {
            if (typesWithMultipleIndexers.ContainsKey(obj.GetType()))
                return FindMatchingIndexerInTypeWithMultipleIndexers(obj, txtIndexerArgs);
            else
                return FindMatchingIndexerInTypeWithSingleIndexer(obj, txtIndexerArgs);
        }

        private static PropertyInfo FindMatchingIndexerInTypeWithSingleIndexer(object obj, string[] txtIndexerArgs)
        {
            PropertyInfo indexer = null;
            try
            {
                PropertyInfo candidate = obj.GetType().GetProperty("Item");
                bool isMatch = (candidate != null) && (indexer.GetIndexParameters().Length == txtIndexerArgs.Length);
                if (isMatch)
                    indexer = candidate;
            }
            catch (AmbiguousMatchException)
            {
                typesWithMultipleIndexers[obj.GetType()] = null;
                indexer = FindMatchingIndexerInTypeWithMultipleIndexers(obj, txtIndexerArgs);
            }

            return indexer;
        }

        const string Item = "Item";

        private static PropertyInfo FindMatchingIndexerInTypeWithMultipleIndexers(object obj, string[] txtIndexerArgs)
        {
            PropertyInfo indexer = null;
            foreach (PropertyInfo prop in obj.GetType().GetProperties())
            {
                bool isIndexer = (prop.Name == Item);
                if (!isIndexer)
                    continue;

                ParameterInfo[] indexerParams = prop.GetIndexParameters();
                bool matchesArgCount = (indexerParams.Length == txtIndexerArgs.Length);
                bool matchesArgTypes;
                if (matchesArgCount)
                {
                    bool nonMatchingArgFound = false;
                    int argIndex = 0;
                    while (!nonMatchingArgFound && argIndex < indexerParams.Length)
                    {
                        Type argType = indexerParams[argIndex].ParameterType;
                        string pathSegmenet = txtIndexerArgs[argIndex];
                        object argValue = NumberParser.ParseValue(argType, pathSegmenet, DefaultFormatter);
                        if (argValue == null)
                            nonMatchingArgFound = true;

                        argIndex++;
                    }

                    matchesArgTypes = !nonMatchingArgFound;
                }
                else
                {
                    matchesArgTypes = false;
                }

                if (matchesArgTypes)
                {
                    indexer = prop;
                    break;
                }
            }

            return indexer;
        }

        #endregion FindMatchingIndexer.

        private static string GetPathString(string[] path)
        {
            string pathString = "";
            foreach (string segment in path)
                pathString += segment + "/";

            if (pathString.Length > 0)
                pathString = pathString.Substring(0, pathString.Length - 1);

            return pathString;
        }

        private static object GetSubComponent(object parentObject, string[] pathTail, out int usedPathSegmentCount, bool logErrorsAsWarnings)
        {
            string propertyOrIndex = pathTail[0];
            object subComponent = null;
            usedPathSegmentCount = 0;

            Type parentType = parentObject.GetType();
            PropertyInfo publicProp = parentType.GetProperty(propertyOrIndex);
            if (publicProp != null)
            {
                subComponent = publicProp.GetValue(parentObject, null);
                usedPathSegmentCount = 1;
            }
            else
            {
                // Find an indexer whose parameters can be parsed by consuming some or all of
                // the segments in the path tail. Prefer indexers with less parameters.
                PropertyInfo indexer = null;
                for (int argsCount = 1; argsCount <= pathTail.Length; argsCount++)
                {
                    string[] args = new string[argsCount];
                    Array.Copy(pathTail, args, argsCount);
                    indexer = FindMatchingIndexer(parentObject, args);
                    if (indexer != null)
                        break;
                }

                ParameterInfo[] indexParameters = (indexer != null) ? indexer.GetIndexParameters() : null;
                bool isIndexerAndPathContainsAllArgs = (indexParameters != null) && (indexParameters.Length > 0) && (indexParameters.Length <= pathTail.Length);
                if (isIndexerAndPathContainsAllArgs)
                {
                    try
                    {
                        object[] index = new object[indexParameters.Length];
                        for (int idxArgument = 0; idxArgument < indexParameters.Length; idxArgument++)
                            index[idxArgument] = Convert.ChangeType(pathTail[idxArgument], indexParameters[idxArgument].ParameterType);

                        subComponent = indexer.GetValue(parentObject, index);
                        usedPathSegmentCount = indexParameters.Length;
                    }
                    catch (Exception e)
                    {
                        if (logErrorsAsWarnings)
                        {
                            Dictionary<string, object> errDetails = new Dictionary<string, object>();
                            for (int idxArgument = 0; idxArgument < indexParameters.Length; idxArgument++)
                                errDetails.Add("Indexer argument #" + (1 + idxArgument), pathTail[idxArgument]);

                            throw new Exception(errDetails.Keys.ToString(), e);
                        }
                    }
                }
            }

            return subComponent;
        }

        private static bool WriteToPropertyOrIndexer(object parentObject, string[] pathTail, object value, bool logErrorsAsWarnings)
        {
            bool isSuccess = false;
            string propertyOrIndex = pathTail[0];
            Type parentType = parentObject.GetType();
            PropertyInfo publicProp = parentType.GetProperty(propertyOrIndex);
            if (publicProp != null)
            {
                isSuccess = TryWriteToProperty(parentObject, publicProp, value, logErrorsAsWarnings);
            }
            else
            {
                PropertyInfo indexer = parentType.GetProperty("Item");
                if (indexer != null)
                    isSuccess = TryWriteToIndexer(parentObject, indexer, value, pathTail, logErrorsAsWarnings);
            }

            return isSuccess;
        }

        private static bool TryWriteToProperty(object parentObject, PropertyInfo publicProp, object value, bool logErrorsAsWarnings)
        {
            bool isSuccess = false;
            if (publicProp.CanWrite)
            {
                try
                {
                    object compatibileValue = ConvertValue(publicProp.PropertyType, value);
                    publicProp.SetValue(parentObject, compatibileValue, null);
                    isSuccess = true;
                }
                catch (Exception e)
                {
                    if (logErrorsAsWarnings)
                    {
                        throw new Exception("Property write failed!", e);
                        //Dictionary<string, object> errDetails = new Dictionary<string, object>();
                        //errDetails.Add("Property", publicProp.Name);
                        //errDetails.Add("Value", value);
                        //Log.AppWarning("ReflectionUtil.WriteToPropertyOrIndexer", e.ToString(), errDetails);
                    }
                }
            }

            return isSuccess;
        }

        private static bool TryWriteToIndexer(object parentObject, PropertyInfo indexer, object value, string[] pathTail, bool logErrorsAsWarnings)
        {
            bool isSuccess = false;
            ParameterInfo[] indexParameters = indexer.GetIndexParameters();
            bool isIndexerAndPathContainsAllArgs = (indexParameters != null) && (indexParameters.Length > 0) && (indexParameters.Length <= pathTail.Length);
            if (isIndexerAndPathContainsAllArgs)
            {
                try
                {
                    object compatibileValue = ConvertValue(indexer.PropertyType, value);
                    object[] index = new object[indexParameters.Length];
                    for (int idxArgument = 0; idxArgument < indexParameters.Length; idxArgument++)
                        index[idxArgument] = Convert.ChangeType(pathTail[idxArgument], indexParameters[idxArgument].ParameterType);

                    indexer.SetValue(parentObject, compatibileValue, index);
                    isSuccess = true;
                }
                catch (Exception e)
                {
                    if (logErrorsAsWarnings)
                    {
                        throw new Exception("Indexer write failed!", e);
                        //Dictionary<string, object> errDetails = new Dictionary<string, object>();
                        //for (int idxArgument = 0; idxArgument < indexParameters.Length; idxArgument++)
                        //    errDetails.Add("Indexer argument #" + (1 + idxArgument), pathTail[idxArgument]);

                        //Log.AppWarning("ReflectionUtil.GetSubComponent", e.ToString(), errDetails);
                    }
                }
            }

            return isSuccess;
        }

        #endregion TrySetValueAtPath.

        #region ConvertValue.

        private static object ConvertValue(Type targetType, object value)
        {
            object compatibileValue;
            Type valueType = Nullable.GetUnderlyingType(targetType);
            bool isNullableValueType = (valueType != null);
            if (isNullableValueType)
                compatibileValue = (value != null) ? Convert.ChangeType(value, valueType, CultureInfo.InvariantCulture) : null;
            else
                compatibileValue = Convert.ChangeType(value, targetType, CultureInfo.InvariantCulture);

            return compatibileValue;
        }

        #endregion ConvertValue.

        #region TrySetPropertyValue.

        /// <summary>
        /// Tries to set the value in the specified public property.
        /// </summary>
        /// <param name="obj">Object to receive the value through public property.</param>
        /// <param name="publicPropertyName">Writeable public property.</param>
        /// <param name="convertibileValue">A value which can be converted to the type which property accepts.</param>
        /// <param name="logErrorsAsWarnings">Whether to log all encountered errors are logged as warnings (see <see cref="Log.AppWarning"/>).</param>
        /// <returns><b>true</b> if the operation was successfull; <b>false</b> otherwise.</returns>
        public static bool TrySetPropertyValue(object obj, string publicPropertyName, object convertibileValue)
        {
            bool isSuccess = false;
            PropertyInfo property = obj.GetType().GetProperty(publicPropertyName);
            if (property != null && property.CanWrite)
            {
                try
                {
                    object value = ConvertValue(property.PropertyType, convertibileValue);
                    property.SetValue(obj, value, null);
                    isSuccess = true;
                }
                catch (Exception e)
                {
                    throw new Exception("Property set failed", e);
                }
            }

            return isSuccess;
        }

        #endregion TrySetPropertyValue.

        #region TryCreateInstance.

        /// <summary>
        /// Tries to locate the specified class in the given assembly and create an instance of it using system activator.
        /// </summary>
        /// <param name="assemblyFullName">The long form of the assembly name.</param>
        /// <param name="classFullName">The <see cref="Type.FullName"/> of the class to locate.</param>
        /// <returns>An instance of <see cref="Object"/> representing the type. <b>null</b> reference if en error occures.</returns>
        /// <remarks>Logs <see cref="Log.AppWarning"/> if an <see cref="Exception"/> occures.</remarks>
        public static object TryCreateInstance(string assemblyFullName, string classFullName)
        {
            object obj;
            if (string.IsNullOrEmpty(assemblyFullName) && string.IsNullOrEmpty(classFullName))
            {
                obj = null;
            }
            else
            {
                try
                {
                    Assembly asm = Assembly.Load(assemblyFullName);
                    obj = asm.CreateInstance(classFullName);
                }
                catch (Exception e)
                {
                    //Log.AppWarning("ReflectionUtil.TryCreateInstance", e.ToString(), null);
                    obj = null;
                    throw new Exception("Create instance failed!", e);
                }
            }

            return obj;
        }

        /// <summary>
        /// Tries to locate the specified class in the given assembly and create an instance of it using system activator.
        /// </summary>
        /// <param name="assemblyStringSetting">Application setting which contains the short or long form of the assembly name.</param>
        /// <param name="classNameSetting">Application setting which contains the full name of the type.</param>
        /// <returns>An instance of <see cref="Object"/> representing the type. <b>null</b> reference if en error occures.</returns>
        /// <remarks>Logs <see cref="Log.AppWarning"/> if an <see cref="Exception"/> occures.</remarks>
        public static object TryCreateInstanceFromAppSettings(string assemblyStringSetting, string classNameSetting)
        {
            if (string.IsNullOrEmpty(assemblyStringSetting))
                throw new ArgumentException("Assembly string settings key is required.");
            if (string.IsNullOrEmpty(classNameSetting))
                throw new ArgumentException("Class name settings key is required.");

            string cfgAssembly = ConfigurationManager.AppSettings[assemblyStringSetting];
            string cfgClass = ConfigurationManager.AppSettings[classNameSetting];
            return TryCreateInstance(cfgAssembly, cfgClass);
        }

        #endregion TryCreateInstance.

        #region CreateDelegate.

        /// <summary>
        /// Creates a delegate of the specified type to represent the specified static method.
        /// </summary>
        /// <typeparam name="T">Delegate type/signature.</typeparam>
        /// <param name="assemblyString">The short or long form of the assembly name.</param>
        /// <param name="className">The full name of the type.</param>
        /// <param name="methodName">The name of the static method to which a delegate is created.</param>
        /// <returns>Delegate.</returns>
        public static T CreateDelegate<T>(string assemblyString, string className, string methodName)
            where T : class
        {
            if (string.IsNullOrEmpty(assemblyString))
                throw new ArgumentException("Assembly string is required.");
            if (string.IsNullOrEmpty(className))
                throw new ArgumentException("Class name is required.");
            if (string.IsNullOrEmpty(methodName))
                throw new ArgumentException("Method name is required.");

            Assembly asm = Assembly.Load(assemblyString);
            if (asm == null)
                throw new InvalidOperationException("Cannot load assembly: " + assemblyString);
            Type cls = asm.GetType(className, true);

            MethodInfo method = cls.GetMethod(methodName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static);
            if (method == null)
                throw new InvalidOperationException("The class '" + className + "' does not contain a static method '" + methodName + "'.");

            T del = Delegate.CreateDelegate(typeof(T), method) as T;
            if (del == null)
                throw new InvalidOperationException("Cannot create delegate.");

            return del;
        }

        /// <summary>
        /// Creates a delegate of the specified type to represent the static method specified in the configuration file.
        /// </summary>
        /// <typeparam name="T">Delegate type/signature.</typeparam>
        /// <param name="assemblyStringSetting">Application setting which contains the short or long form of the assembly name.</param>
        /// <param name="classNameSetting">Application setting which contains the full name of the type.</param>
        /// <param name="methodNameSetting">Application setting which contains the name of the static method to which a delegate is created.</param>
        /// <returns>Delegate.</returns>
        public static T CreateDelegateFromAppSettings<T>(string assemblyStringSetting, string classNameSetting, string methodNameSetting)
            where T : class
        {
            if (string.IsNullOrEmpty(assemblyStringSetting))
                throw new ArgumentException("Assembly string settings key is required.");
            if (string.IsNullOrEmpty(classNameSetting))
                throw new ArgumentException("Class name settings key is required.");
            if (string.IsNullOrEmpty(methodNameSetting))
                throw new ArgumentException("Method name settings key is required.");

            string cfgAssembly = ConfigurationManager.AppSettings[assemblyStringSetting];
            string cfgClass = ConfigurationManager.AppSettings[classNameSetting];
            string cfgMethod = ConfigurationManager.AppSettings[methodNameSetting];
            return CreateDelegate<T>(cfgAssembly, cfgClass, cfgMethod);
        }

        /// <summary>
        /// Tries to creates a delegate of the specified type to represent the static method specified in the configuration file.
        /// </summary>
        /// <typeparam name="T">Delegate type/signature.</typeparam>
        /// <param name="assemblyStringSetting">Application setting which contains the short or long form of the assembly name.</param>
        /// <param name="classNameSetting">Application setting which contains the full name of the type.</param>
        /// <param name="methodNameSetting">Application setting which contains the name of the static method to which a delegate is created.</param>
        /// <returns>Delegate. <b>null</b> if settings are not configured, or if an error occures.</returns>
        /// <remarks>Logs <see cref="Log.AppWarning"/> if an <see cref="Exception"/> occures.</remarks>
        public static T TryCreateDelegateFromAppSettings<T>(string assemblyStringSetting, string classNameSetting, string methodNameSetting)
            where T : class
        {
            if (string.IsNullOrEmpty(assemblyStringSetting))
                throw new ArgumentException("Assembly string settings key is required.");
            if (string.IsNullOrEmpty(classNameSetting))
                throw new ArgumentException("Class name settings key is required.");
            if (string.IsNullOrEmpty(methodNameSetting))
                throw new ArgumentException("Method name settings key is required.");

            string cfgAssembly = ConfigurationManager.AppSettings[assemblyStringSetting];
            string cfgClass = ConfigurationManager.AppSettings[classNameSetting];
            string cfgMethod = ConfigurationManager.AppSettings[methodNameSetting];
            if (string.IsNullOrEmpty(cfgAssembly) || string.IsNullOrEmpty(cfgClass) || string.IsNullOrEmpty(cfgMethod))
                return null;

            try
            {
                return CreateDelegate<T>(cfgAssembly, cfgClass, cfgMethod);
            }
            catch
            {
                //Log.AppWarning("ReflectionUtil.TryCreateDelegateFromAppSettings", e.ToString(), null);
                return null;
            }
        }

        #endregion CreateDelegate.

        #region Json converter.

        public static string GetStringValue(this Enum value)
        {
            // Get the type
            Type type = value.GetType();

            // Get fieldinfo for this type
            FieldInfo fieldInfo = type.GetField(value.ToString());
            JsonEnumNameAttribute[] attribs = fieldInfo.GetCustomAttributes(
                typeof(JsonEnumNameAttribute), false) as JsonEnumNameAttribute[];

            return attribs.Length > 0 ? attribs[0].Name : null; // i have more values
        }

        #endregion Json converter.
    }

    /// <summary>
    /// Contains commonly used generic procedure and function delegates.
    /// </summary>
    public static class Delegates
    {
        #region Procedures.

        /// <summary>
        /// Represents a parameterless method that doesn't return a value.
        /// </summary>
        public delegate void Procedure();

        /// <summary>
        /// Represents a method that accepts one argument and doesn't return a value.
        /// </summary>
        /// <typeparam name="TArg">Argument type.</typeparam>
        /// <param name="arg">Method argument.</param>
        public delegate void Procedure<TArg>(TArg arg);

        /// <summary>
        /// Represents a method that accepts two arguments and doesn't return a value.
        /// </summary>
        /// <typeparam name="TArg1">Type of the first argument.</typeparam>
        /// <typeparam name="TArg2">Type of the second argument.</typeparam>
        /// <param name="arg1">First argument.</param>
        /// <param name="arg2">Second argument.</param>
        public delegate void Procedure<TArg1, TArg2>(TArg1 arg1, TArg2 arg2);

        /// <summary>
        /// Represents a method that accepts three arguments and doesn't return a value.
        /// </summary>
        /// <typeparam name="TArg1">Type of the first argument.</typeparam>
        /// <typeparam name="TArg2">Type of the second argument.</typeparam>
        /// <typeparam name="TArg3">Type of the third argument.</typeparam>
        /// <param name="arg1">First argument.</param>
        /// <param name="arg2">Second argument.</param>
        /// <param name="arg3">Third argument.</param>
        public delegate void Procedure<TArg1, TArg2, TArg3>(TArg1 arg1, TArg2 arg2, TArg3 arg3);

        /// <summary>
        /// Represents a method that accepts four arguments and doesn't return a value.
        /// </summary>
        /// <typeparam name="TArg1">Type of the first argument.</typeparam>
        /// <typeparam name="TArg2">Type of the second argument.</typeparam>
        /// <typeparam name="TArg3">Type of the third argument.</typeparam>
        /// <typeparam name="TArg4">Type of the fourth argument.</typeparam>
        /// <param name="arg1">First argument.</param>
        /// <param name="arg2">Second argument.</param>
        /// <param name="arg3">Third argument.</param>
        /// <param name="arg4">Fourth argument.</param>
        public delegate void Procedure<TArg1, TArg2, TArg3, TArg4>(TArg1 arg1, TArg2 arg2, TArg3 arg3, TArg4 arg4);

        /// <summary>
        /// Represents a method that accepts five arguments and doesn't return a value.
        /// </summary>
        /// <typeparam name="TArg1">Type of the first argument.</typeparam>
        /// <typeparam name="TArg2">Type of the second argument.</typeparam>
        /// <typeparam name="TArg3">Type of the third argument.</typeparam>
        /// <typeparam name="TArg4">Type of the fourth argument.</typeparam>
        /// <typeparam name="TArg5">Type of the fifth argument.</typeparam>
        /// <param name="arg1">First argument.</param>
        /// <param name="arg2">Second argument.</param>
        /// <param name="arg3">Third argument.</param>
        /// <param name="arg4">Fourth argument.</param>
        /// <param name="arg5">Fifth argument.</param>
        public delegate void Procedure<TArg1, TArg2, TArg3, TArg4, TArg5>(TArg1 arg1, TArg2 arg2, TArg3 arg3, TArg4 arg4, TArg5 arg5);

        #endregion Procedures.

        #region Functions.

        /// <summary>
        /// Represents a parameterless method that returns a value of the specified type.
        /// </summary>
        /// <typeparam name="TRetVal">Type of the return value.</typeparam>
        /// <returns>A value of the specified type.</returns>
        public delegate TRetVal Function<TRetVal>();

        /// <summary>
        /// Represents a method that accepts one argument and returns a value of the specified type.
        /// </summary>
        /// <typeparam name="TRetVal">Type of the return value.</typeparam>
        /// <typeparam name="TArg">Argument type.</typeparam>
        /// <param name="arg">Method argument.</param>
        /// <returns>A value of the specified type.</returns>
        public delegate TRetVal Function<TRetVal, TArg>(TArg arg);

        /// <summary>
        /// Represents a method that accepts two arguments and returns a value of the specified type.
        /// </summary>
        /// <typeparam name="TRetVal">Type of the return value.</typeparam>
        /// <typeparam name="TArg1">Type of the first argument.</typeparam>
        /// <typeparam name="TArg2">Type of the second argument.</typeparam>
        /// <param name="arg1">First argument.</param>
        /// <param name="arg2">Second argument.</param>
        /// <returns>A value of the specified type.</returns>
        public delegate TRetVal Function<TRetVal, TArg1, TArg2>(TArg1 arg1, TArg2 arg2);

        /// <summary>
        /// Represents a method that accepts three arguments and returns a value of the specified type.
        /// </summary>
        /// <typeparam name="TRetVal">Type of the return value.</typeparam>
        /// <typeparam name="TArg1">Type of the first argument.</typeparam>
        /// <typeparam name="TArg2">Type of the second argument.</typeparam>
        /// <typeparam name="TArg3">Type of the third argument.</typeparam>
        /// <param name="arg1">First argument.</param>
        /// <param name="arg2">Second argument.</param>
        /// <param name="arg3">Third argument.</param>
        /// <returns>A value of the specified type.</returns>
        public delegate TRetVal Function<TRetVal, TArg1, TArg2, TArg3>(TArg1 arg1, TArg2 arg2, TArg3 arg3);

        /// <summary>
        /// Represents a method that accepts four arguments and returns a value of the specified type.
        /// </summary>
        /// <typeparam name="TRetVal">Type of the return value.</typeparam>
        /// <typeparam name="TArg1">Type of the first argument.</typeparam>
        /// <typeparam name="TArg2">Type of the second argument.</typeparam>
        /// <typeparam name="TArg3">Type of the third argument.</typeparam>
        /// <typeparam name="TArg4">Type of the fourh argument.</typeparam>
        /// <param name="arg1">First argument.</param>
        /// <param name="arg2">Second argument.</param>
        /// <param name="arg3">Third argument.</param>
        /// <param name="arg4">Fourth argument.</param>
        /// <returns>A value of the specified type.</returns>
        public delegate TRetVal Function<TRetVal, TArg1, TArg2, TArg3, TArg4>(TArg1 arg1, TArg2 arg2, TArg3 arg3, TArg4 arg4);

        /// <summary>
        /// Represents a method that accepts five arguments and returns a value of the specified type.
        /// </summary>
        /// <typeparam name="TRetVal">Type of the return value.</typeparam>
        /// <typeparam name="TArg1">Type of the first argument.</typeparam>
        /// <typeparam name="TArg2">Type of the second argument.</typeparam>
        /// <typeparam name="TArg3">Type of the third argument.</typeparam>
        /// <typeparam name="TArg4">Type of the fourth argument.</typeparam>
        /// <typeparam name="TArg5">Type of the fifth argument.</typeparam>
        /// <param name="arg1">First argument.</param>
        /// <param name="arg2">Second argument.</param>
        /// <param name="arg3">Third argument.</param>
        /// <param name="arg4">Fourth argument.</param>
        /// <param name="arg5">Fifth argument.</param>
        /// <returns>A value of the specified type.</returns>
        public delegate TRetVal Function<TRetVal, TArg1, TArg2, TArg3, TArg4, TArg5>(TArg1 arg1, TArg2 arg2, TArg3 arg3, TArg4 arg4, TArg5 arg5);

        #endregion Functions.
    }

    /// <summary>
    /// Represents a hierarchical two-level collection of keys and values.
    /// </summary>
    /// <typeparam name="T2ndLevelKey">The type of the highest level key in the dictionary.</typeparam>
    /// <typeparam name="T1stLevelKey">The type of the lower level key in the dictionary.</typeparam>
    /// <typeparam name="TValue">The type of the values in the dictionary.</typeparam>
    public sealed class LevelTwoDictionary<T2ndLevelKey, T1stLevelKey, TValue> : ICloneable
    {
        #region Fields.

        IDictionary<T2ndLevelKey, IDictionary<T1stLevelKey, TValue>> l2Dictionary = new Dictionary<T2ndLevelKey, IDictionary<T1stLevelKey, TValue>>();

        #endregion Fields.

        #region CTor.

        /// <summary>
        /// Initializes a new instance of <b>LevelTwoDictionary</b> class.
        /// </summary>
        public LevelTwoDictionary()
        {
        }

        #endregion CTor.

        #region Indexer.

        /// <summary>
        /// Gets or sets the value associated with the specified keys.
        /// </summary>
        /// <param name="l2key">Highest level key in the dictionary.</param>
        /// <param name="l1key">Lower level key in the dictionary.</param>
        /// <returns>The value associated with the specified keys. If any of the specified keys is not found,
        /// <b>null</b> is returned, and a <b>set</b> operation creates a new element with the specified keys.</returns>
        public TValue this[T2ndLevelKey l2key, T1stLevelKey l1key]
        {
            get
            {
                TValue val = default(TValue);
                if (this.l2Dictionary.ContainsKey(l2key))
                {
                    IDictionary<T1stLevelKey, TValue> l1Dictionary = this.l2Dictionary[l2key];
                    if (l1Dictionary.ContainsKey(l1key))
                        val = l1Dictionary[l1key];
                }

                return val;
            }
            set
            {
                IDictionary<T1stLevelKey, TValue> l1Dictionary;
                if (this.l2Dictionary.ContainsKey(l2key))
                {
                    l1Dictionary = this.l2Dictionary[l2key];
                }
                else
                {
                    l1Dictionary = new Dictionary<T1stLevelKey, TValue>();
                    this.l2Dictionary.Add(l2key, l1Dictionary);
                }

                if (l1Dictionary.ContainsKey(l1key))
                    l1Dictionary[l1key] = value;
                else
                    l1Dictionary.Add(l1key, value);
            }
        }

        #endregion Indexer.

        #region Methods.

        /// <summary>
        /// Removes all keys and values below the specified 2nd level key.
        /// </summary>
        /// <param name="l2key">Highest level key in the dictionary.</param>
        /// <returns><b>true</b> if the element is successfully found and removed; otherwise, <b>false</b>.
        /// This method returns <b>false</b> if any of the specified keys is not found in the dictionary.</returns>
        public bool Remove(T2ndLevelKey l2key)
        {
            return this.l2Dictionary.Remove(l2key);
        }

        /// <summary>
        /// Removes the value with the specified keys from the dictionary.
        /// </summary>
        /// <param name="l2key">Highest level key in the dictionary.</param>
        /// <param name="l1key">Lower level key in the dictionary.</param>
        /// <returns><b>true</b> if the element is successfully found and removed; otherwise, <b>false</b>.
        /// This method returns <b>false</b> if any of the specified keys is not found in the dictionary.</returns>
        public bool Remove(T2ndLevelKey l2key, T1stLevelKey l1key)
        {
            if (this.l2Dictionary.ContainsKey(l2key))
                return this.l2Dictionary[l2key].Remove(l1key);
            else
                return false;
        }

        /// <summary>
        /// Removes all keys and values from the dictionary.
        /// </summary>
        public void Clear()
        {
            this.l2Dictionary.Clear();
        }

        /// <summary>
        /// Gets first level key-value pairs below the specified 2nd level key.
        /// </summary>
        /// <param name="l2key">Highest level key in the dictionary.</param>
        /// <returns>Dictionary. <b>null</b> if the specified 2nd level key does not exist.</returns>
        public IDictionary<T1stLevelKey, TValue> Get1stLevelDictionary(T2ndLevelKey l2key)
        {
            if (this.l2Dictionary.ContainsKey(l2key))
                return this.l2Dictionary[l2key];
            else
                return null;
        }

        /// <summary>
        /// Copies all entries from the given dictionary into the current instance.
        /// </summary>
        /// <param name="source">Another dictionary.</param>
        /// <remarks>If a key-combination already exists in the current instance, it will be overwritten.</remarks>
        public void CopyFrom(LevelTwoDictionary<T2ndLevelKey, T1stLevelKey, TValue> source)
        {
            foreach (KeyValuePair<T2ndLevelKey, IDictionary<T1stLevelKey, TValue>> l2SourceEntry in source.l2Dictionary)
            {
                T2ndLevelKey l2key = l2SourceEntry.Key;
                IDictionary<T1stLevelKey, TValue> l1SourceDictionary = l2SourceEntry.Value;
                foreach (KeyValuePair<T1stLevelKey, TValue> l1KeyAndValue in l1SourceDictionary)
                    this[l2key, l1KeyAndValue.Key] = l1KeyAndValue.Value;
            }
        }

        /// <summary>
        /// Creates a new object that is a copy of the current instance.
        /// </summary>
        /// <returns>A new object that is a copy of this instance.</returns>
        public object Clone()
        {
            LevelTwoDictionary<T2ndLevelKey, T1stLevelKey, TValue> clone = new LevelTwoDictionary<T2ndLevelKey, T1stLevelKey, TValue>();
            clone.CopyFrom(this);
            return clone;
        }

        #endregion Methods.

        #region Properties.

        /// <summary>
        /// Gets the number of elements in the highest (2nd) level.
        /// </summary>
        public int Count
        {
            get
            {
                return this.l2Dictionary.Count;
            }
        }

        #endregion Properties.
    }

    /// <summary>
    /// Binding pair for bound dictionary <see cref="DictionaryBindingList"/>.
    /// </summary>
    /// <typeparam name="TKey">Key type</typeparam>
    /// <typeparam name="TValue">Pair type</typeparam>
    public sealed class BindingPair<TKey, TValue>
    {
        private readonly TKey key;
        private readonly IDictionary<TKey, TValue> data;

        /// <summary>
        /// Creates new instance of this class.
        /// </summary>
        /// <param name="key">Key of item.</param>
        /// <param name="data">Dictionary connected to this item.</param>
        public BindingPair(TKey key, IDictionary<TKey, TValue> data)
        {
            this.key = key;
            this.data = data;
        }

        /// <summary>
        /// Key of item in dictionary.
        /// </summary>
        public TKey Key { get { return key; } }

        /// <summary>
        /// Value of item in dictionary.
        /// </summary>
        public TValue Value
        {
            get
            {
                TValue value;
                data.TryGetValue(key, out value);
                return value;
            }
            set { data[key] = value; }
        }
    }

    /// <summary>
    /// Bound dictionary.
    /// </summary>
    /// <typeparam name="TKey">Key type.</typeparam>
    /// <typeparam name="TValue">Value type.</typeparam>
    public sealed class DictionaryBindingList<TKey, TValue> : BindingList<BindingPair<TKey, TValue>>
    {
        private readonly IDictionary<TKey, TValue> data;

        /// <summary>
        /// Creates new instance of this class and raises <see cref="BindingList<T>.ListChanged"/> event.
        /// </summary>
        /// <param name="data">Dictionary with items to be bound.</param>
        public DictionaryBindingList(IDictionary<TKey, TValue> data)
        {
            this.data = data;
            this.Reset();
        }

        /// <summary>
        /// Resets this class and raises <see cref="BindingList<T>.ListChanged"/> event.
        /// </summary>
        public void Reset()
        {
            bool oldRaise = this.RaiseListChangedEvents;
            this.RaiseListChangedEvents = false;
            try
            {
                this.Clear();
                foreach (TKey key in data.Keys)
                {
                    this.Add(new BindingPair<TKey, TValue>(key, data));
                }
            }
            finally
            {
                this.RaiseListChangedEvents = oldRaise;
                this.ResetBindings();
            }
        }
    }

    /// <summary>
    /// Utility class for storing object properties and applying them to object instances.
    /// </summary>
    /// <remarks>The class can store values of all properties and single-parameter indexers (collections).</remarks>
    public sealed class ObjectProperties
    {
        #region Fields.

        IDictionary<string, object> properties = new Dictionary<string, object>();
        LevelTwoDictionary<string, object, object> indexers = new LevelTwoDictionary<string, object, object>();

        #endregion Fields.

        #region CTor.

        /// <summary>
        /// Initializes a new instance of <b>ObjectProperties</b> class.
        /// </summary>
        public ObjectProperties()
        {
        }

        #endregion CTor.

        #region Properties.

        /// <summary>
        /// Gets a collection of property names and values.
        /// </summary>
        public IDictionary<string, object> Properties
        {
            get
            {
                return this.properties;
            }
        }

        /// <summary>
        /// Gets a collection of indexer names (collection property which exposes <b>Item</b> property) and values.
        /// </summary>
        public LevelTwoDictionary<string, object, object> Indexers
        {
            get
            {
                return this.indexers;
            }
        }

        #endregion Properties.

        #region WriteToObject.

        /// <summary>
        /// Writes property values to the given object.
        /// </summary>
        /// <param name="obj">Object whose propertis are to be set to match the values stored in the <b>ObjectProperties</b> instance.</param>
        /// <remarks>The properties which do not exist in the given object are skipped.</remarks>
        public void WriteToObject(object obj)
        {
            if (properties.Count == 0 && indexers.Count == 0)
                return;

            PropertyInfo[] allProperties = obj.GetType().GetProperties();
            foreach (PropertyInfo prop in allProperties)
            {
                if (!prop.CanWrite)
                    continue;

                ParameterInfo[] indexerArgs = prop.GetIndexParameters();
                if (indexerArgs.Length == 0)
                {
                    // Simple setter.
                    object providedValue = this.properties.ContainsKey(prop.Name) ? this.properties[prop.Name] : null;
                    if (providedValue != null)
                    {
                        object compatibileValue = Convert.ChangeType(providedValue, prop.PropertyType);
                        prop.SetValue(obj, compatibileValue, null);
                    }
                }
                else if (indexerArgs.Length == 1)
                {
                    // Single-parameter indexer.
                    Type argType = indexerArgs[0].ParameterType;
                    IDictionary<object, object> indexesAndValues = this.indexers.Get1stLevelDictionary(prop.Name);
                    foreach (KeyValuePair<object, object> idxAndVal in indexesAndValues)
                    {
                        object compatibileIndexValue = Convert.ChangeType(idxAndVal.Key, argType);
                        object compatibilePropertyValue = Convert.ChangeType(idxAndVal.Value, prop.PropertyType);
                        prop.SetValue(obj, compatibilePropertyValue, new object[] { compatibileIndexValue });
                    }
                }
            }
        }

        /// <summary>
        /// Writes property values to the given object.
        /// </summary>
        /// <param name="obj">Object whose propertis are to be set to match the values stored in the <b>ObjectProperties</b> instance.</param>
        /// <param name="ignoreErrors">Indicates whether all exceptions encountered during writing and type conversion should be ignored.</param>
        /// <remarks>The properties which do not exist in the given object are skipped.</remarks>
        public void WriteToObject(object obj, bool ignoreErrors)
        {
            if (properties.Count == 0 && indexers.Count == 0)
                return;

            PropertyInfo[] allProperties = obj.GetType().GetProperties();
            foreach (PropertyInfo prop in allProperties)
            {
                if (!prop.CanWrite)
                    continue;

                ParameterInfo[] indexerArgs = prop.GetIndexParameters();
                try
                {
                    if (indexerArgs.Length == 0)
                    {
                        // Simple setter.
                        object providedValue = this.properties.ContainsKey(prop.Name) ? this.properties[prop.Name] : null;
                        if (providedValue != null)
                        {
                            object compatibileValue = Convert.ChangeType(providedValue, prop.PropertyType);
                            prop.SetValue(obj, compatibileValue, null);
                        }
                    }
                    else if (indexerArgs.Length == 1)
                    {
                        // Single-parameter indexer.
                        Type argType = indexerArgs[0].ParameterType;
                        IDictionary<object, object> indexesAndValues = this.indexers.Get1stLevelDictionary(prop.Name);
                        foreach (KeyValuePair<object, object> idxAndVal in indexesAndValues)
                        {
                            object compatibileIndexValue = Convert.ChangeType(idxAndVal.Key, argType);
                            object compatibilePropertyValue = Convert.ChangeType(idxAndVal.Value, prop.PropertyType);
                            prop.SetValue(obj, compatibilePropertyValue, new object[] { compatibileIndexValue });
                        }
                    }
                }
                catch
                {
                    if (!ignoreErrors)
                        throw;
                }
            }
        }

        #endregion WriteToObject.
    }

    /// <summary>
    /// Provides a generic utility class that is used to store two related objects.
    /// </summary>
    /// <typeparam name="TKey">Type of the first object of the pair.</typeparam>
    /// <typeparam name="TValue">Type of the second object of the pair.</typeparam>
    /// <remarks>The <b>Pair</b> class is used as a basic structure to store two related objects. You can use the
    /// Pair class in your own code anywhere that you need a structure to contain two related objects.</remarks>
    [Serializable]
    public sealed class Pair<TKey, TValue>
    {
        #region Fields.

        /// <summary>
        /// Gets or sets the first object of the pair.
        /// </summary>
        TKey first;

        /// <summary>
        /// Gets or sets the second object of the pair.
        /// </summary>
        TValue second;

        #endregion Fields.

        #region Constructors.

        /// <summary>
        /// Creates a new, uninitialized instance of the <b>Pair</b> class.
        /// </summary>
        public Pair()
        {
        }

        /// <summary>
        /// Initializes a new instance of the <b>Pair</b> class, using the specified object pair.
        /// </summary>
        /// <param name="first">Object assigned to <see cref="First"/>.</param>
        /// <param name="second">Object assigned to <see cref="Second"/>.</param>
        public Pair(TKey first, TValue second)
        {
            this.first = first;
            this.second = second;
        }

        #endregion Constructors.

        #region Properties.

        /// <summary>
        /// Gets or sets the first object of the pair.
        /// </summary>
        public TKey First
        {
            get
            {
                return this.first;
            }
            set
            {
                this.first = value;
            }
        }

        /// <summary>
        /// Gets or sets the second object of the pair.
        /// </summary>
        public TValue Second
        {
            get
            {
                return this.second;
            }
            set
            {
                this.second = value;
            }
        }

        #endregion Properties.
    }

    /// <summary>
    /// Compresses and decompresses data using GZIP algorithm.
    /// </summary>
    public static class GZipUtil
    {
        #region Compress.

        /// <summary>
        /// Compresses data using GZIP algorithm.
        /// </summary>
        /// <param name="dataToCompress">Data to compress.</param>
        /// <returns>Compressed data.</returns>
        public static byte[] Compress(byte[] dataToCompress)
        {
            MemoryStream gzipBuffer = new MemoryStream();

            GZipStream zipper = new GZipStream(gzipBuffer, CompressionMode.Compress, true);
            zipper.Write(dataToCompress, 0, dataToCompress.Length);
            // Close() adds additional 10 bytes to the end of the stream.
            // Close gzip and underlying gzipBuffer before reading from the buffer, ie. converting it to a byte array.
            zipper.Close();

            // Convert data in the underlying gzipBuffer to byte array.
            gzipBuffer.Seek(0, SeekOrigin.Begin);
            byte[] compressedData = gzipBuffer.ToArray();

            gzipBuffer.Close();
            return compressedData;
        }

        #endregion Compress.

        #region Decompress.

        /// <summary>
        /// Decompresses data which has been compressed using GZIP algorithm.
        /// </summary>
        /// <param name="compressedData">Compressed data.</param>
        /// <returns>Decompressed data.</returns>
        public static byte[] Decompress(byte[] compressedData)
        {
            MemoryStream gzipBuffer = new MemoryStream();
            gzipBuffer.Write(compressedData, 0, compressedData.Length);
            gzipBuffer.Seek(0, SeekOrigin.Begin);
            GZipStream unzipper = new GZipStream(gzipBuffer, CompressionMode.Decompress);

            byte[] decompressedData = CopyStreamToByteArray(unzipper);
            unzipper.Close();
            gzipBuffer.Close();

            return decompressedData;
        }

        private static byte[] CopyStreamToByteArray(Stream source)
        {
            MemoryStream destination = new MemoryStream();
            const int kilobyte = 1024;
            byte[] readBuffer = new byte[kilobyte];
            int numberOfBytesReadFromStream;
            while ((numberOfBytesReadFromStream = source.Read(readBuffer, 0, readBuffer.Length)) > 0)
            {
                destination.Write(readBuffer, 0, numberOfBytesReadFromStream);
            }
            byte[] arData = destination.ToArray();
            destination.Close();
            return arData;
        }

        #endregion Decompress.
    }

    /// <summary>
    /// Gets the current date and time for the current application.
    /// </summary>
    /// <remarks>Prefer using <see cref="Time.Now"/> in your code instead of <see cref="DateTime.Now"/>.
    /// Currently, both return the same value, but in the future <b>Time</b> class will be upgraded to
    /// support configurable time adjustments and time synchronization with other servers.</remarks>
    public static class Time
    {
        /// <summary>
        /// Gets a DateTime object that is set to the current date and time on this computer, expressed as the local time.
        /// </summary>
        public static DateTime Now
        {
            get
            {
                return DateTime.Now;
            }
        }
    }

    /// <summary>
    /// Provides common text processing functionalities.
    /// </summary>
    public static class TextUtil
    {
        #region TrimNullableString.

        /// <summary>
        /// Trims and parses nullable strings.
        /// </summary>
        /// <param name="s">String or <b>null</b> reference.</param>
        /// <returns>Trimmed string or <b>null</b> if empty string is provided or yielded.</returns>
        public static string TrimNullableString(string s)
        {
            if (string.IsNullOrEmpty(s))
                return null;

            s = s.Trim();
            return (s.Length > 0) ? s : null;
        }

        #endregion TrimNullableString.

        #region EnsureSuffix.

        /// <summary>
        /// Checks whether the text ends with the specified suffix. If not, it will be appended.
        /// </summary>
        /// <param name="text">Text to check. Nulls are converted to empty strings.</param>
        /// <param name="suffix">Suffix. Nullable.</param>
        /// <returns>A string which ends with the specified suffix.</returns>
        public static string EnsureSuffix(string text, string suffix)
        {
            if (text == null)
                text = "";

            if (!string.IsNullOrEmpty(suffix) && !text.EndsWith(suffix))
                text += suffix;

            return text;
        }

        #endregion EnsureSuffix.

        #region ReplaceNewLine.

        /// <summary>
        /// Replaces new line and/or carriage return characters with the specified value.
        /// </summary>
        /// <param name="text">Text to correct. Nullable.</param>
        /// <param name="newLineReplacementValue">A string to replace all occurrences of <b>\r\n</b>, <b>\n\r</b>, <b>\n</b> and <b>\r</b> strings. Nullable.</param>
        /// <returns>A string without <b>\r\n</b>, <b>\n\r</b>, <b>\n</b> and <b>\r</b> strings.</returns>
        public static string ReplaceNewLine(string text, string newLineReplacementValue)
        {
            if (text == null)
                text = "";
            if (newLineReplacementValue == null)
                newLineReplacementValue = "";

            text = text.Replace("\r\n", newLineReplacementValue);
            text = text.Replace("\n\r", newLineReplacementValue);
            text = text.Replace("\n", newLineReplacementValue);
            text = text.Replace("\r", newLineReplacementValue);
            return text;
        }

        #endregion ReplaceNewLine.

        #region RemovePrefix.

        /// <summary>
        /// Checks whether the text starts with the specified prefix. If it does, it will be removed.
        /// </summary>
        /// <param name="text">Text to check. Nullable.</param>
        /// <param name="prefix">Prefix. Nullable.</param>
        /// <returns>A string from which the prefix has been removed. <b>null</b> if input text is <b>null</b>. Empty string if prefix is equal to input text.</returns>
        public static string RemovePrefix(string text, string prefix)
        {
            string output;
            if (string.IsNullOrEmpty(text))
                output = text;
            else if (string.IsNullOrEmpty(prefix))
                output = text;
            else if (text.StartsWith(prefix))
                output = text.Remove(0, prefix.Length);
            else
                output = text;

            return output;
        }

        #endregion RemovePrefix.

        #region SetSmall

        public static string SetSmall(string txt, int leng)
        {
            if (txt == null)
                return "";

            if (txt.Length > leng)
                return txt.Substring(0, leng - 1) + "...";
            else
            {
                if (txt.Trim().Length < 1)
                    return " ";
                else
                    return txt;
            }
        }

        public static string FindP(string txt, string start, string ending)
        {
            return FindP(txt, start, ending, false);
        }

        public static string FindP(string txt, string start, string ending, bool trimData)
        {
            string patMatch = Regex.Escape(start) + "(.*?)" + Regex.Escape(ending);
            string retVal = "";
            if (Regex.IsMatch(txt, patMatch))
                retVal = Regex.Match(txt, patMatch).Groups[0].Value;
            if (trimData)
                retVal = retVal.Trim();

            return retVal;
        }

        public static string GetLead(string strTekst, int lngLen, int lngLenADD)
        {
            bool bInTag = false;
            string sTmpOut = "";
            string sTmpOutReal = "";
            string sTmpOutPart = "";
            string sTmpEl = "";
            int x = 0;
            for (x = 0; x <= strTekst.Length - 1; x++)
            {
                sTmpEl = strTekst.Substring(x, 1);

                if (bInTag == false)
                {
                    if (sTmpEl == "<")
                    {
                        bInTag = true;
                    }
                    else
                    {
                        sTmpOut = sTmpOut + sTmpEl;
                    }
                }
                else
                {
                    if (sTmpEl == ">")
                    {
                        bInTag = false;
                    }
                }
            }
            if (lngLen > sTmpOut.Length)
                lngLen = sTmpOut.Length;
            sTmpOutReal = sTmpOut.Substring(0, lngLen);

            sTmpOutPart = FindP(sTmpOut, sTmpOutReal, ".");
            if (sTmpOutPart.Length > lngLenADD | (sTmpOut.Contains(".") == false & string.IsNullOrEmpty(sTmpOutPart)))
            {
                sTmpOutPart = FindP(sTmpOut, sTmpOutReal, "!");
                if (sTmpOutPart.Length > lngLenADD | (sTmpOut.Contains("!") == false & string.IsNullOrEmpty(sTmpOutPart)))
                {
                    sTmpOutPart = FindP(sTmpOut, sTmpOutReal, "?");
                    if (sTmpOutPart.Length > lngLenADD | (sTmpOut.Contains("?") == false & string.IsNullOrEmpty(sTmpOutPart)))
                    {
                        sTmpOutPart = FindP(sTmpOut, sTmpOutReal, ",");
                        if (sTmpOutPart.Length > lngLenADD | (sTmpOut.Contains(",") == false & string.IsNullOrEmpty(sTmpOutPart)))
                        {
                            sTmpOutPart = FindP(sTmpOut, sTmpOutReal, " ");
                            if (sTmpOutPart.Length > lngLenADD | (sTmpOut.Contains(" ") == false & string.IsNullOrEmpty(sTmpOutPart)))
                            {
                                if (lngLenADD > sTmpOutPart.Length)
                                    lngLenADD = sTmpOutPart.Length;
                                sTmpOutPart = sTmpOutPart.Substring(0, lngLenADD);
                            }
                        }
                    }
                }
            }
            return sTmpOutReal + sTmpOutPart + "...";
        }

        #endregion SetSmall

        #region HrZnakovi

        public static byte Asc(char src)
        {
            return (System.Text.Encoding.GetEncoding("iso-8859-1").GetBytes(src + "")[0]);
        }

        public static char Chr(byte src)
        {
            return (System.Text.Encoding.GetEncoding("iso-8859-1").GetChars(new byte[] { src })[0]);
        }

        public static string SetCroSign(string strTekst)
        {
            string txt = strTekst;
            txt = txt.Replace("š", "&scaron;");
            txt = txt.Replace("đ", "&#273;");
            txt = txt.Replace("ć", "&#263;");
            txt = txt.Replace("č", "&#269;");
            txt = txt.Replace("Ž", "&#381;");
            txt = txt.Replace("Š", "&Scaron;");
            txt = txt.Replace("Đ", "&#272;");
            txt = txt.Replace("Ć", "&#262;");
            txt = txt.Replace("Č", "&#268;");
            txt = txt.Replace("ž", "&#382;");
            return txt;
        }

        public static string RetCroSign(string strTekst)
        {
            string txt = strTekst;
            txt = txt.Replace("&#262;", "Ć");
            txt = txt.Replace("&#269;", "č");
            txt = txt.Replace("&#268;", "Č");
            txt = txt.Replace("&#263;", "ć");
            txt = txt.Replace("&scaron;", "š");
            txt = txt.Replace("&Scaron;", "Š");
            txt = txt.Replace("&#382;", "ž");
            txt = txt.Replace("&#381;", "Ž");
            txt = txt.Replace("&#273;", "đ");
            txt = txt.Replace("&#272;", "Đ");
            return txt;
        }

        #endregion HrZnakovi

        #region Base64 encoding

        public static string base64Encode(string data)
        {
            try
            {
                byte[] encData_byte = new byte[data.Length];
                encData_byte = System.Text.Encoding.UTF8.GetBytes(data);
                string encodedData = Convert.ToBase64String(encData_byte);
                return encodedData;
            }
            catch (Exception e)
            {
                throw new Exception("Error in base64Encode" + e.Message);
            }
        }

        public static string base64Encode(string data, bool WithUriEncode)
        {
            if (WithUriEncode)
            {
                data = Uri.EscapeDataString(data);
                return base64Encode(data);
            }
            else
                return base64Encode(data);
        }

        public static string base64Decode(string data)
        {
            try
            {
                System.Text.UTF8Encoding encoder = new System.Text.UTF8Encoding();
                System.Text.Decoder utf8Decode = encoder.GetDecoder();

                byte[] todecode_byte = Convert.FromBase64String(data);
                int charCount = utf8Decode.GetCharCount(todecode_byte, 0, todecode_byte.Length);
                char[] decoded_char = new char[charCount];
                utf8Decode.GetChars(todecode_byte, 0, todecode_byte.Length, decoded_char, 0);
                string result = new String(decoded_char);
                return result;
            }
            catch (Exception e)
            {
                throw new Exception("Error in base64Decode" + e.Message);
            }
        }

        #endregion Base64 encoding

        #region String hashing

        public static string GetSHA1(string text)
        {
            UnicodeEncoding UE = new UnicodeEncoding();
            byte[] hashValue = null;
            byte[] message = UE.GetBytes(text);

            SHA1Managed hashString = new SHA1Managed();
            string hex = "";

            hashValue = hashString.ComputeHash(message);
            foreach (byte x in hashValue)
            {
                hex += String.Format("{0:x2}", x);
            }
            return hex;
        }

        public static byte[] GetSHA1Byte(string text)
        {
            UnicodeEncoding UE = new UnicodeEncoding();
            byte[] message = UE.GetBytes(text);

            SHA1Managed hashString = new SHA1Managed();
            return hashString.ComputeHash(message);
        }

        #endregion String hashing

        #region Email sending.

        public static void SendMail(string MailTo, string MailSubject, string MailBody)
        {
            SmtpClient smp = new SmtpClient(ConfigurationManager.AppSettings["BL.MailSMTP"]);
            MailMessage msg1 = new MailMessage(ConfigurationManager.AppSettings["BL.MailFrom"], MailTo, MailSubject, MailBody);
            msg1.BodyEncoding = System.Text.Encoding.GetEncoding("iso-8859-2");
            msg1.Priority = MailPriority.Normal;
            msg1.IsBodyHtml = true;
            smp.Send(msg1);
            msg1 = null;
            smp = null;
        }

        public static void SendMail(string MailFrom, string MailTo, string MailSubject, string MailBody)
        {
            SmtpClient smp = new SmtpClient(ConfigurationManager.AppSettings["BL.MailSMTP"]);
            MailMessage msg1 = new MailMessage(MailFrom, MailTo, MailSubject, MailBody);
            msg1.BodyEncoding = System.Text.Encoding.GetEncoding("iso-8859-2");
            msg1.Priority = MailPriority.Normal;
            msg1.IsBodyHtml = true;
            smp.Send(msg1);
            msg1 = null;
            smp = null;
        }

        public static bool ValidateEmail(string EmailToCheck)
        {
            bool isObeyed = true;
            string regexMatch = "^(?(\"\")(\"\".+?\"\"@)|(([0-9a-zA-Z]((\\.(?!\\.))|[-!#\\$%&'\\*\\+/=\\?\\^`\\{\\}\\|~\\w])*)(?<=[0-9a-zA-Z])@))(?(\\[)(\\[(\\d{1,3}\\.){3}\\d{1,3}\\])|(([0-9a-zA-Z][-\\w]*[0-9a-zA-Z]\\.)+[a-zA-Z]{2,6}))$";

            if (!System.Text.RegularExpressions.Regex.IsMatch(EmailToCheck, regexMatch))
                isObeyed = false;

            return isObeyed;
        }

        #endregion Email sending.

        #region IsNumeric.

        /// <summary>
        /// Checks if string is numeric value (e.g. Double, Single, Integer, Long...)
        /// </summary>
        /// <param name="txt">String to check.</param>
        /// <returns>True if is numeric.</returns>
        public static bool IsNumeric(string txt)
        {
            double Num;
            return double.TryParse(txt, out Num);
        }

        #endregion IsNumeric.

        #region Link stuff

        /// <summary>
        /// Creates user friendly SEO link attribute
        /// </summary>
        /// <param name="txt">Text for SEO linking</param>
        /// <param name="leng">Size of SEO string to use</param>
        /// <returns>User friendly, URL safe, SEO link attribute</returns>
        public static string CreateSEOLink(string txt, int leng)
        {
            if (TextUtil.IsNumeric(txt))
                return txt;

            int x = 0;
            char subs = '\0';
            string strOut = "";

            txt = txt.Replace("č", "c");
            txt = txt.Replace("ć", "c");
            txt = txt.Replace("š", "s");
            txt = txt.Replace("ž", "z");
            txt = txt.Replace("đ", "d");

            txt = txt.Replace("&#268;", "c");
            txt = txt.Replace("&#269;", "C");
            txt = txt.Replace("&#262;", "C");
            txt = txt.Replace("&#263;", "c");
            txt = txt.Replace("&scaron;", "s");
            txt = txt.Replace("&Scaron;", "S");
            txt = txt.Replace("&#381;", "Z");
            txt = txt.Replace("&#382;", "z");
            txt = txt.Replace("&#273;", "d");
            txt = txt.Replace("&#272;", "D");

            if (leng > txt.Length)
                leng = txt.Length;

            for (x = 0; x < leng; x++)
            {
                subs = txt.Substring(x, 1).ToUpper().ToCharArray()[0];
                if (subs == '=' || subs == ',' || subs == '-')
                    strOut = strOut + txt.Substring(x, 1);
                else if (TextUtil.Asc(subs) > 47 && TextUtil.Asc(subs) < 58)
                    strOut = strOut + txt.Substring(x, 1);
                else if (TextUtil.Asc(subs) > 64 && TextUtil.Asc(subs) < 91)
                    strOut = strOut + txt.Substring(x, 1);
                else if (TextUtil.Asc(subs) == 32)
                    strOut = strOut + "-";
                else if (TextUtil.Asc(subs) == 142)
                    strOut = strOut + txt.Substring(x, 1);
                else if (TextUtil.Asc(subs) == 138)
                    strOut = strOut + txt.Substring(x, 1);
                else if (TextUtil.Asc(subs) == 208)
                    strOut = strOut + txt.Substring(x, 1);
            }

            if (string.IsNullOrEmpty(strOut))
                strOut = "link";

            return strOut;
        }

        #endregion Link stuff

        #region Ip address stuff.

        /// <summary>
        /// Converts string Ip address in form of XXX.XXX.XXX.XXX to it's long value.
        /// </summary>
        /// <param name="ipAddress">String ip address.</param>
        /// <returns>Long ip address</returns>
        public static long IpAddrToLong(string ipAddress)
        {
            long fullIp = 0;
            List<string> ipParts = new List<string>(ipAddress.Split('.'));
            if (ipParts.Count != 4)
                throw new FormatException("Ip address was not in correct format.");
            try
            {
                fullIp = long.Parse(ipParts[0]) << 24;
                fullIp += long.Parse(ipParts[1]) << 16;
                fullIp += long.Parse(ipParts[2]) << 8;
                fullIp += long.Parse(ipParts[3]);
            }
            catch (Exception)
            {
                return 0;
            }
            return fullIp;
        }

        /// <summary>
        /// Converts long ip address to it's string representation.
        /// </summary>
        /// <param name="numIpAddress">Long ip address in range [0-4294967295].</param>
        /// <returns>String ip address in form of XXX.XXX.XXX.XXX.</returns>
        public static string LongToIpAddr(long numIpAddress)
        {
            string ipAddress = "";
            if (numIpAddress < 0 || (numIpAddress >> 32) > 0)
                throw new FormatException("Num IP address was not in valid range [0-4294967295].");

            ipAddress = (numIpAddress % 256).ToString();
            numIpAddress /= 256;
            ipAddress = (numIpAddress % 256).ToString() + "." + ipAddress;
            numIpAddress /= 256;
            ipAddress = (numIpAddress % 256).ToString() + "." + ipAddress;
            numIpAddress /= 256;
            ipAddress = (numIpAddress % 256).ToString() + "." + ipAddress;

            return ipAddress;
        }

        #endregion Ip address stuff.
    }

    /// <summary>
    /// Message text and format with values that can be formatted using any culture.
    /// </summary>
    /// <remarks>Typically used to pass messages that contain real numbers and dates from business
    /// logic layer to UI layer. UI layer decides how the values are to be formatted, while
    /// business layer creates the content of message.</remarks>
    [Serializable]
    public sealed class FormattedMessage
    {
        #region Members.

        IMessageFormatter formatter;
        string messageFormat;
        ArrayList values = new ArrayList();

        #endregion Members.

        #region Constructors.

        /// <summary>
        /// Initializes a new instance of the <b>FormattedMessage</b> class.
        /// </summary>
        /// <param name="messageFormat">Message text and format. The message format must obey the rules of the
        /// <see cref="System.String.Format(string, object)"/> method.</param>
        public FormattedMessage(string messageFormat)
        {
            this.messageFormat = (messageFormat != null) ? messageFormat : "";
            this.formatter = new MessageFormatter();
        }

        /// <summary>
        /// Initializes a new instance of the <b>FormattedMessage</b> class.
        /// </summary>
        /// <param name="messageFormat">Message text and format. The message format must obey the rules of the
        /// <see cref="System.String.Format(string, object)"/> method.</param>
        /// <param name="values">Values which are to be inserted into <b>MessageFormat</b> and formatted by <b>Formatter</b>.</param>
        public FormattedMessage(string messageFormat, params object[] values)
        {
            this.messageFormat = (messageFormat != null) ? messageFormat : "";
            this.formatter = new MessageFormatter();
            if (values != null)
            {
                foreach (object val in values)
                    this.values.Add(val);
            }
        }

        /// <summary>
        /// Initializes a new instance of the <b>FormattedMessage</b> class.
        /// </summary>
        /// <param name="messageFormat">Message text and format. The message format must obey the rules of the
        /// <see cref="System.String.Format(string, object)"/> method.</param>
        /// <param name="formatter">An <b>IMessageFormatter</b> object that formattes the values contained in the message.</param>
        /// <param name="values">Values which are to be inserted into <b>MessageFormat</b> and formatted by <b>Formatter</b>.</param>
        public FormattedMessage(string messageFormat, IMessageFormatter formatter, params object[] values)
        {
            this.messageFormat = (messageFormat != null) ? messageFormat : "";
            this.formatter = (formatter != null) ? formatter : new MessageFormatter();
            if (values != null)
            {
                foreach (object val in values)
                    this.values.Add(val);
            }
        }

        #endregion Constructors.

        #region ToString.

        /// <summary>
        /// Converts an instance of <b>FormattedMessage</b> to a <b>System.String</b>.
        /// </summary>
        /// <returns>String with formatted values.</returns>
        public override string ToString()
        {
            return ToString(this.formatter);
        }

        /// <summary>
        /// Converts an instance of <b>FormattedMessage</b> to a <b>System.String</b>.
        /// </summary>
        /// <param name="formatter">The <b>IMessageFormatter</b> that formattes the values contained in the message.</param>
        /// <returns>String with formatted values.</returns>
        public string ToString(IMessageFormatter formatter)
        {
            string[] formattedValues = new string[this.values.Count];
            for (int i = 0; i < formattedValues.Length; i++)
                formattedValues[i] = formatter.Format(this.values[i]);

            return string.Format(this.messageFormat, formattedValues);
        }

        #endregion ToString.

        #region Append.

        /// <summary>
        /// Appends the given message to the end of this instance.
        /// </summary>
        /// <param name="message">Message with values to be appended.</param>
        public void Append(FormattedMessage message)
        {
            if (message == null)
                return;

            FormattedMessage newMessage = this + message;
            this.messageFormat = newMessage.messageFormat;
            this.formatter = newMessage.formatter;
            this.values = newMessage.values;
        }

        /// <summary>
        /// Appends the given message to the end of this instance.
        /// </summary>
        /// <param name="message">String to be appended.</param>
        public void Append(string message)
        {
            if (message == null)
                return;

            this.messageFormat += message;
        }

        /// <summary>
        /// Appends the given message to the end of this instance.
        /// </summary>
        /// <param name="messageFormat">Message text and format. The message format must obey the rules of the <see cref="System.String.Format(string, object)"/> method.</param>
        /// <param name="values">Array of values which are to be inserted into message format.</param>
        public void Append(string messageFormat, params object[] values)
        {
            if (messageFormat == null)
                return;

            Append(new FormattedMessage(messageFormat, values));
        }

        #endregion Append.

        #region Concatenation operator.

        /// <summary>
        /// Concatenates two messages into a new one that contains all the values of the original messages.
        /// </summary>
        /// <param name="lhs">The first message.</param>
        /// <param name="rhs">The second message.</param>
        /// <returns>Concatenated message.</returns>
        public static FormattedMessage operator +(FormattedMessage lhs, FormattedMessage rhs)
        {
            FormattedMessage newMessage = null;
            if (lhs == null && rhs == null)
            {
                // null + null = null
                newMessage = null;
            }
            else
            {
                if (lhs == null)
                {
                    // null + rhs = rhs
                    newMessage = rhs;
                }
                else if (rhs == null)
                {
                    // lhs + null = lhs
                    newMessage = lhs;
                }
                else
                {
                    // lhs + rhs
                    // lhs formatter will be used.

                    // All indices int rhs message format are increased.
                    // Otherwise this would occur:  "Left {0}. Right{0}.
                    // After indices are increased: "Left {0}. Right{1}.
                    string rhsFormat = rhs.messageFormat;
                    if (lhs.values.Count > 0 && rhs.values.Count > 0)
                        rhsFormat = IncreaseParameterIndices(rhsFormat, lhs.values.Count);

                    string newFormat = lhs.messageFormat + rhsFormat;
                    newMessage = new FormattedMessage(newFormat);
                    newMessage.formatter = lhs.formatter;
                    foreach (object val in lhs.values)
                        newMessage.values.Add(val);
                    foreach (object val in rhs.values)
                        newMessage.values.Add(val);
                }
            }

            return newMessage;
        }

        private static string IncreaseParameterIndices(string msgFormat, int increaseBy)
        {
            int[] ascendingIndices = GetNumbersInCurlyBraces(msgFormat);
            Array.Sort(ascendingIndices);

            // Increase indices. Greatest ones first. Otherwise overlapping will occure.
            string newFormat = msgFormat;
            for (int i = ascendingIndices.Length - 1; i >= 0; i--)
            {
                int oldIdx = ascendingIndices[i];
                int newIdx = oldIdx + increaseBy;
                newFormat = newFormat.Replace("{" + oldIdx.ToString() + "}", "{" + newIdx + "}");
            }
            return newFormat;
        }

        private static int[] GetNumbersInCurlyBraces(string msgFormat)
        {
            Regex digitsInBraces = new Regex(@"\{\d{1,}\}");
            MatchCollection matches = digitsInBraces.Matches(msgFormat);
            int[] numbers = new int[matches.Count];

            for (int i = 0; i < numbers.Length; i++)
            {
                string sNumber = matches[i].Value.Substring(1, matches[i].Value.Length - 2);
                numbers[i] = int.Parse(sNumber);
            }

            return numbers;
        }

        #endregion Concatenation operator.

        #region Cast operators.

        /// <summary>
        /// Casts an instance of <b>FormattedMessage</b> to a <b>System.String</b>.
        /// </summary>
        /// <param name="message">Message to be converted to <b>System.String</b>.</param>
        /// <returns>String with formatted values.</returns>
        /// <remarks>Implicit cast operators allow the <b>FormattedMessage</b> to be used anywhere where strings are used.</remarks>
        public static implicit operator string(FormattedMessage message)
        {
            return message.ToString();
        }

        /// <summary>
        /// Casts a <b>System.String</b> to an instance of <b>FormattedMessage</b>.
        /// </summary>
        /// <param name="str">String.</param>
        /// <returns>FormattedMessage.</returns>
        /// <remarks>Implicit cast operators allow the <b>FormattedMessage</b> to be used anywhere where strings are used.</remarks>
        public static implicit operator FormattedMessage(string str)
        {
            return new FormattedMessage(str);
        }

        #endregion Cast operators.

        #region Properties.

        /// <summary>
        /// Gets or sets the <b>IMessageFormatter</b> that formattes the values contained in the message.
        /// </summary>
        public IMessageFormatter Formatter
        {
            get
            {
                return this.formatter;
            }
            set
            {
                this.formatter = (value != null) ? value : new MessageFormatter();
            }
        }

        /// <summary>
        /// Gets or sets the message text and format. The message format must obey the rules of the <see cref="System.String.Format(string, object)"/> method.
        /// </summary>
        public string MessageFormat
        {
            get
            {
                return this.messageFormat;
            }
            set
            {
                this.messageFormat = (value != null) ? value : "";
            }
        }

        /// <summary>
        /// Gets or sets the list of values which are to be inserted into <b>MessageFormat</b> and formatted by <b>Formatter</b>.
        /// </summary>
        public ArrayList Values
        {
            get
            {
                return this.values;
            }
        }

        #endregion Properties.
    }

    /// <summary>
    /// Contains format providers for common types and implements formatting logic.
    /// </summary>
    public interface IMessageFormatter
    {
        #region Methods.

        /// <summary>
        /// Formats the given value.
        /// </summary>
        /// <param name="val">Value to be formatted.</param>
        /// <returns>String representation of the given value.</returns>
        string Format(object val);

        /// <summary>
        /// Gets format used to format values of the given type.
        /// </summary>
        /// <param name="t">Type of value to be formatted.</param>
        /// <returns>Value format.</returns>
        string GetFormat(Type t);

        #endregion Methods.

        #region Properties.

        /// <summary>
        /// An <see cref="IFormatProvider"/> object used for all types unless specific provider exists.
        /// </summary>
        IFormatProvider DefaultProvider
        {
            get;
        }

        /// <summary>
        /// An <see cref="IFormatProvider"/> object used to format integer values.
        /// </summary>
        IFormatProvider IntProvider
        {
            get;
        }

        /// <summary>
        /// Format for integer values.
        /// </summary>
        string IntFormat
        {
            get;
        }

        /// <summary>
        /// <see cref="NumberStyles"/> which indicates the permitted format of strings representing integer values.
        /// </summary>
        NumberStyles IntStyle
        {
            get;
        }

        /// <summary>
        /// An <see cref="IFormatProvider"/> object used to format floating point numbers.
        /// </summary>
        IFormatProvider RealProvider
        {
            get;
        }

        /// <summary>
        /// Format for floating point numbers.
        /// </summary>
        string RealFormat
        {
            get;
        }

        /// <summary>
        /// <see cref="NumberStyles"/> which indicates the permitted format of strings representing floating point numbers.
        /// </summary>
        NumberStyles RealStyle
        {
            get;
        }

        /// <summary>
        /// An <see cref="IFormatProvider"/> object used to format DateTime values.
        /// </summary>
        IFormatProvider DateProvider
        {
            get;
        }

        /// <summary>
        /// Format for DateTime values.
        /// </summary>
        string DateFormat
        {
            get;
        }

        /// <summary>
        /// <see cref="DateTimeStyles"/> which indicates the permitted format of strings representing <b>DateTime</b> values.
        /// </summary>
        DateTimeStyles DateStyle
        {
            get;
        }

        #endregion Properties.
    }

    /// <summary>
    /// Defines format providers and styles for common types and implements formatting logic.
    /// </summary>
    [Serializable]
    public class MessageFormatter : IMessageFormatter
    {
        #region Fields.

        IFormatProvider defaultProvider;
        IFormatProvider intProvider;
        string intFormat;
        NumberStyles intStyle;
        IFormatProvider realProvider;
        string realFormat;
        NumberStyles realStyle;
        IFormatProvider dateProvider;
        string dateFormat;
        DateTimeStyles dateStyle;
        private string shortTimeFormat = "hh:mm";

        #endregion Fields.

        #region Constructors.

        /// <summary>
        /// Initializes a new instance of <b>MessageFormatter</b> class.
        /// </summary>
        /// <remarks>Uses default system format providers for all types.</remarks>
        public MessageFormatter()
        {
            shortTimeFormat = "hh:mm";
            Init(null, null, null, null, null, null, null, NumberStyles.Integer, NumberStyles.Number, DateTimeStyles.None);
        }

        /// <summary>
        /// Initializes a new instance of <b>MessageFormatter</b> class.
        /// </summary>
        /// <param name="defaultProvider">Format provider used for all types. <b>Nullable.</b></param>
        public MessageFormatter(IFormatProvider defaultProvider)
        {
            Init(defaultProvider, null, null, null, null, null, null, NumberStyles.Integer, NumberStyles.Number, DateTimeStyles.None);
        }

        /// <summary>
        /// Initializes a new instance of <b>MessageFormatter</b> class.
        /// </summary>
        /// <param name="defaultProvider">Format provider used for all types unless specific provider for a type is asigned. <b>Nullable.</b></param>
        /// <param name="intFormat">Format for integer values. <b>Nullable.</b></param>
        /// <param name="realFormat">Format for floating point numbers. <b>Nullable.</b></param>
        /// <param name="dateFormat">Format for DateTime values. <b>Nullable.</b></param>
        public MessageFormatter(IFormatProvider defaultProvider, string intFormat, string realFormat, string dateFormat)
        {
            Init(defaultProvider, null, null, null, intFormat, realFormat, dateFormat, NumberStyles.Integer, NumberStyles.Number, DateTimeStyles.None);
        }

        /// <summary>
        /// Initializes a new instance of <b>MessageFormatter</b> class.
        /// </summary>
        /// <param name="defaultProvider">Format provider used for all types unless specific provider for a type is asigned. <b>Nullable.</b></param>
        /// <param name="intProvider">Format provider used to format integer values. <b>Nullable.</b></param>
        /// <param name="realProvider">Format provider used to format floating point numbers. <b>Nullable.</b></param>
        /// <param name="dateProvider">Format provider used to format DateTime values. <b>Nullable.</b></param>
        /// <param name="intFormat">Format for integer values. <b>Nullable.</b></param>
        /// <param name="realFormat">Format for floating point numbers. <b>Nullable.</b></param>
        /// <param name="dateFormat">Format for DateTime values. <b>Nullable.</b></param>
        public MessageFormatter(IFormatProvider defaultProvider, IFormatProvider intProvider, IFormatProvider realProvider, IFormatProvider dateProvider, string intFormat, string realFormat, string dateFormat)
        {
            Init(defaultProvider, intProvider, realProvider, dateProvider, intFormat, realFormat, dateFormat, NumberStyles.Integer, NumberStyles.Number, DateTimeStyles.None);
        }

        /// <summary>
        /// Initializes a new instance of <b>MessageFormatter</b> class.
        /// </summary>
        /// <param name="defaultProvider">Format provider used for all types unless specific provider for a type is asigned. <b>Nullable.</b></param>
        /// <param name="intProvider">Format provider used to format integer values. <b>Nullable.</b></param>
        /// <param name="realProvider">Format provider used to format floating point numbers. <b>Nullable.</b></param>
        /// <param name="dateProvider">Format provider used to format DateTime values. <b>Nullable.</b></param>
        /// <param name="intFormat">Format for integer values. <b>Nullable.</b></param>
        /// <param name="realFormat">Format for floating point numbers. <b>Nullable.</b></param>
        /// <param name="dateFormat">Format for DateTime values. <b>Nullable.</b></param>
        /// <param name="intStyle"><see cref="NumberStyles"/> which indicates the permitted format of strings representing
        /// integer values. A typical value to specify is <see cref="System.Globalization.NumberStyles.Integer"/>.</param>
        /// <param name="realStyle"><see cref="NumberStyles"/> which indicates the permitted format of strings representing
        /// floating point numbers. A typical value to specify is <see cref="System.Globalization.NumberStyles.Number"/>.</param>
        /// <param name="dateStyle"><see cref="DateTimeStyles"/> which indicates the permitted format of strings representing
        /// <b>DateTime</b> values. A typical value to specify is <see cref="DateTimeStyles.None"/>.</param>
        public MessageFormatter(IFormatProvider defaultProvider, IFormatProvider intProvider, IFormatProvider realProvider, IFormatProvider dateProvider,
            string intFormat, string realFormat, string dateFormat, NumberStyles intStyle, NumberStyles realStyle, DateTimeStyles dateStyle)
        {
            Init(defaultProvider, intProvider, realProvider, dateProvider, intFormat, realFormat, dateFormat, intStyle, realStyle, dateStyle);
        }

        private void Init(IFormatProvider defaultProvider, IFormatProvider intProvider, IFormatProvider realProvider, IFormatProvider dateProvider,
            string intFormat, string realFormat, string dateFormat, NumberStyles intStyle, NumberStyles realStyle, DateTimeStyles dateStyle)
        {
            this.defaultProvider = (defaultProvider == null) ? CultureInfo.CurrentCulture : defaultProvider;
            this.intProvider = (intProvider == null) ? this.defaultProvider : intProvider;
            this.realProvider = (realProvider == null) ? this.defaultProvider : realProvider;
            this.dateProvider = (dateProvider == null) ? this.defaultProvider : dateProvider;
            this.intFormat = intFormat;
            this.realFormat = realFormat;
            this.dateFormat = dateFormat;
            this.intStyle = intStyle;
            this.realStyle = realStyle;
            this.dateStyle = dateStyle;
        }

        #endregion Constructors.

        #region Format.

        /// <summary>
        /// Formats the given value.
        /// </summary>
        /// <param name="val">Value to be formatted.</param>
        /// <returns>String representation of the given value.</returns>
        public string Format(object val)
        {
            if (val == null)
                return "";
            if (IsDate(val))
                return Convert.ToDateTime(val).ToString(this.dateFormat, this.dateProvider);
            else if (IsReal(val))
                return Convert.ToDouble(val).ToString(this.realFormat, this.realProvider);
            else if (IsInteger(val))
                return Convert.ToInt64(val).ToString(this.intFormat, this.intProvider);
            else
                return val.ToString();
        }

        #endregion Format.

        #region GetFormat.

        /// <summary>
        /// Gets format used to format values of the given type.
        /// </summary>
        /// <param name="t">Type of value to be formatted.</param>
        /// <returns>Value format.</returns>
        public string GetFormat(Type t)
        {
            if (TypeUtil.IsDate(t))
                return this.dateFormat;
            else if (TypeUtil.IsFloatingPointNumber(t))
                return this.realFormat;
            else if (TypeUtil.IsInteger(t))
                return this.intFormat;
            else
                return null;
        }

        private bool IsDate(object val)
        {
            if (val is DateTime)
                return true;
            else
                return false;
        }

        private bool IsReal(object val)
        {
            if (val is Single || val is Double || val is Decimal)
                return true;
            else
                return false;
        }

        private bool IsInteger(object val)
        {
            if (val is Int32 || val is Byte || val is Int16 || val is Int64 || val is SByte || val is UInt16 || val is UInt32 || val is Int64)
                return true;
            else
                return false;
        }

        #endregion GetFormat.

        #region Properties.

        /// <summary>
        /// Gets or sets the format provider used for all types unless specific provider exists. <b>Nullable.</b>
        /// </summary>
        /// <remarks>If set to <b>null</b>, default system format will be used.</remarks>
        public IFormatProvider DefaultProvider
        {
            get
            {
                return this.defaultProvider;
            }
            set
            {
                this.defaultProvider = (value == null) ? CultureInfo.CurrentCulture : value;
            }
        }

        /// <summary>
        /// Gets or sets the format provider used to format integer values. <b>Nullable.</b>
        /// </summary>
        public IFormatProvider IntProvider
        {
            get
            {
                return this.intProvider;
            }
            set
            {
                this.intProvider = value;
            }
        }

        /// <summary>
        /// Gets or sets the format for integer values. <b>Nullable.</b>
        /// </summary>
        public string IntFormat
        {
            get
            {
                return this.intFormat;
            }
            set
            {
                this.intFormat = value;
            }
        }

        /// <summary>
        /// Gets or sets <see cref="NumberStyles"/> which indicates the permitted format of strings representing integer values.
        /// A typical value to specify is <see cref="System.Globalization.NumberStyles.Integer"/>.
        /// </summary>
        public NumberStyles IntStyle
        {
            get
            {
                return this.intStyle;
            }
            set
            {
                this.intStyle = value;
            }
        }

        /// <summary>
        /// Gets or sets the format provider used to format floating point numbers. <b>Nullable.</b>
        /// </summary>
        public IFormatProvider RealProvider
        {
            get
            {
                return this.realProvider;
            }
            set
            {
                this.realProvider = value;
            }
        }

        /// <summary>
        /// Gets or sets the format for floating point numbers. <b>Nullable.</b>
        /// </summary>
        public string RealFormat
        {
            get
            {
                return this.realFormat;
            }
            set
            {
                this.realFormat = value;
            }
        }

        /// <summary>
        /// Gets or sets <see cref="NumberStyles"/> which indicates the permitted format of strings representing floating point numbers.
        /// A typical value to specify is <see cref="System.Globalization.NumberStyles.Number"/>.
        /// </summary>
        public NumberStyles RealStyle
        {
            get
            {
                return this.realStyle;
            }
            set
            {
                this.realStyle = value;
            }
        }

        /// <summary>
        /// Gets or sets the format provider used to format DateTime values. <b>Nullable.</b>
        /// </summary>
        public IFormatProvider DateProvider
        {
            get
            {
                return this.dateProvider;
            }
            set
            {
                this.dateProvider = value;
            }
        }

        /// <summary>
        /// Gets or sets the format for DateTime values. <b>Nullable.</b>
        /// </summary>
        public string DateFormat
        {
            get
            {
                return this.dateFormat;
            }
            set
            {
                this.dateFormat = value;
            }
        }

        /// <summary>
        /// Gets or sets <see cref="DateTimeStyles"/> which indicates the permitted format of strings representing <b>DateTime</b> values.
        /// A typical value to specify is <see cref="DateTimeStyles.None"/>.
        /// </summary>
        public DateTimeStyles DateStyle
        {
            get
            {
                return this.dateStyle;
            }
            set
            {
                this.dateStyle = value;
            }
        }

        /// <summary>
        /// Gets or sets the format for ShortTimeFormat values. <b>Nullable.</b>
        /// </summary>
        public string ShortTimeFormat
        {
            get
            {
                return this.shortTimeFormat;
            }
            set
            {
                this.shortTimeFormat = value;
            }
        }

        #endregion Properties.
    }
}
